list

An empty list can be constructed as follows: list = [];

Nesting is also possible but each nested list will become a tuple which means the ‘list’ will be immutable. ThingsDB does this because it wants to update all changes to subscribers and finds the subscribers by the parent object where the change is made. Since the parent of a nested ‘list’ is another list, the thing holding the list would not be found.

Functions

Function Description
choice Return a random item from a list.
each Iterate over all items in a list.
every Check if all items pass a given test.
extend Add an array with items to the end of a list and returns the new length.
filter Return a new list with items that passed a given test.
find Return the first item that passed a given test.
findindex Return the index of the first item that passed a given test.
indexof Return the index of a given value, or nil if not found.
len Return the length of the list.
map Return a new list with the results of calling a provided closure on every item.
pop Remove the last item from a list and returns that item.
push Add new items to the end of a list and returns the new length.
reduce Execute a reducer function on each item, resulting in a single output value.
remove Remove the first item that passed a given test and returns that item.
some Check if at least one item passes a given test.
sort Return a new sorted list.
splice Change a list by removing or replacing existing items and/or adding new items.

It is not possible to change a list while the list is in use, for example:
tmp = [1, 2, 3]; tmp.map(|i| tmp.push(i));
…will raise bad_data_err() (cannot change type list while the value is being used)

Reference versus copy

It might be useful to understand when ThingsDB uses a reference to a list, and when it makes copy. As long as a list is used as a variable, then ThingsDB uses a reference to the list. If a list will be assigned to a thing, or if a list which is assigned to a thing, will be assigned to a variable, then a copy will be made. For example:

a = [1, 2];
b = a;  // both `a` and `b` are variable so a *reference* is used.
.c = a;  // `c` is assigned, so a *copy* will be made.
a.push(3);  // note that `.c` is not affected because `.c` is a *copy*.

// Return the values
[a, b, .c];

Response in JSON format:

[
    [1, 2, 3],
    [1, 2, 3],
    [1, 2]
]

The same is true for when a list is used within a closure. For example:

a = [];    // `list` assigned to a variable

// `a` stays a variable, so a reference will be used
a2 = range(3).reduce(|arr, val| {arr.push(val); arr;}, a);   // [0, 1, 2]

assert (a == a2);   // both `a` and `a2` are a reference to the same list

And when a list is assigned to a thing…

.b = [];   // `list` assigned to a thing

// `.b` will be assigned to `arr`, so in the first iteration a *copy* will be made
b2 = range(3).reduce(|arr, val| {arr.push(val); arr;}, .b);  // [0, 1, 2]

assert (.b != b2);  // [] != [0, 1, 2]