### The List Intrinsic Class

"List" is a native TADS 3 datatype. Lists are actually instances of the intrinsic class List, which means that you can call methods defined by the List intrinsic class on list objects.

### Value Semantics

Lists have "value semantics," which means that a given list value is immutable. Any operation that appears to modify a list value is actually creating a new list value, and leaving the original value unchanged. This behavior makes it very easy to work with lists, because you never have to worry about how many variables or properties refer to a list even if several variables refer to a list value, each variable effectively has its own private copy of the list, so changes made to one variable's list won't affect any others. This also means that you can pass a list to a function without having to worry about whether the function will modify the list, and similarly that you can modify a list passed in as an argument to your functions without having to worry about how the changes will affect the caller.

This is discussed in more detail in the Vector intrinsic class section.

### List Iterations

A List is a subclass of Collection, so you can use the createIterator() method to create an Iterator to iterate over the elements of the list. The Iterator that a List creates is called an IndexedIterator, and visits the elements of the list in index order (the first element visited is the element at index 1, the second is the element at index 2, and so forth).

### List Methods

List is a subclass of Collection, and thus defines the Collection methods. In addition, List defines the methods shown below.

append(val) appends the value val to this list, returning the resulting list. This is almost the same as using the "+" operator to append val to the list, but differs in that this method always treats val as a single new element, even if val is a list. Consider the following:

       local x = [1, 2, 3];

       local y = x + [4, 5];

       local z = x.append([4, 5]);

In this example, the value of y is the list [1, 2, 3, 4, 5]: if the value on the right of a "+" operator is a list, the "+" operator appends each value of the list as a separate element. In contrast, the value of z is [1, 2, 3, [4, 5]], because the append() method always treats its argument as a single element of the new list.

Note that you can achieve the same effect using the "+" operator by constructing a new list for the right operand:

       local y2 = x + [[4, 5]];

This will ensure that the value of y2 is the same as the value of z: [1, 2, 3, [4, 5]]. However, the append() method is more efficient than constructing a new list for the right operand of "+", because it is not necessary to construct the intermediate list using append().

appendUnique(lst) appends the elements of the list lst to this list, returning a new list consisting only of the unique elements of the combination. Each value appearing in the result list will appear in the result list only once. (The same effect could be obtained by concatenating the two lists with the "+" operator then applying getUnique() to the result, but this method is more efficient because it avoids constructing the fully concatenated list as an intermediate value.)

car() returns the first element of the list. If the list has no elements, returns nil.

cdr() returns the "tail" of the list; that is, the rest of the list after removing the first element. If the list has no elements, returns nil. This function is almost the same as sublist(2), except that sublist() would return an empty list if given an empty list, whereas cdr() returns nil in this case.

countOf(val) returns the number of elements whose values equal val.

countWhich(cond) returns the number of elements for which the callback function cond returns a non-false value (anything but nil or 0). For each element, this method calls the callback, passing the current element as the argument. If the callback returns anything but nil or 0, the method counts the element. After invoking the callback for each element, the method returns the resulting count.

indexOf(val) returns the index of the first element of the list equal to the given value. If val does not appear anywhere in the list, the method returns nil. The first element is at index 1.

indexWhich(cond) finds the first element for which the given condition is true. The method iterates through the elements of the list, starting at the first element and proceeding in order, and applies the callback function cond to each element. The callback takes one argument, which is the value of the list element, and returns a condition result value. For each element, if the callback function returns a non-false value (i.e., any value except nil or zero), the method immediately stops the iteration and returns the index of that element. If the callback returns a false value (nil or zero) for every element of the list, the method returns nil.

forEach(func) invokes the callback function func(value) for each element, in order from first to last, passing the value of one element as value to the callback on each invocation. The callback function takes one argument, which is the current element, and returns no value. This method returns no value. This method is a convenient means of executing some code for each element of the list.

forEachAssoc(func) invokes the callback function func(index, value) for each element, in order from first to last, passing each element's index and value to the function func. The callback function returns no value. This method returns no value. This method is a convenient means of executing some code for each element of the list; unlike forEach(), this method provides its callback with the index as well as the value for each element it visits.

getUnique() returns a new list consisting of the unique elements of the original list. For each value in the original list, the value will appear in the new list only once. The order of the elements in the new list is that of the first appearances of the unique elements of the original list. For example, if the original list is [1, 5, 2, 5, 3, 5, 4, 5], this method will return [1, 5, 2, 3, 4].

insertAt(index, val1, val2, ) returns a new list which results from inserting the given values (val1, val2, and so on) into the existing list before the element at the position given by index. At least one value argument is required; if multiple value arguments are provided, the values are inserted into the list in the same order in which they appear in the arguments.

If index is 1, the values are inserted before the first element of the existing list (this means that insertAt(1, x) is equivalent to prepend(x)), and if index is equal to the number of elements in the original list plus 1, the values are inserted after the last element of the existing list (so lst.insertAt(lst.length() + 1, x) is equivalent to lst.append(x)). An index value less than 1 or greater than the number of elements in the list plus 1 is illegal and results in an index out of range exception.

    Because the new elements are inserted before any existing element at the insertion point, the index in the result list of the first element inserted always equals index.  For example, consider this statement:

      lst = lst.insertAt(5, 'a', 'b', 'c');

    After this statement is executed, lst[5] will be 'a'.

Note that, if any of the values to be inserted are themselves lists, each one is inserted as a single list-valued element, in the same manner as append(val) and prepend(val).

intersect(lst2) returns a new list consisting of the intersection of this list and lst2; that is, a list consisting of the elements common to both this list and lst2. lst2 must also be a list. If the two lists have no elements in common, the result is an empty list. If an element of the shorter list (or, if the lists are of equal length, this list) appears more than once in the shorter list, and that element value also appears in the longer list, then the element will be in the result list the same number of times that it is in the shorter list. An element repeated in the longer list will not be repeated in the result list.

lastIndexOf(val) returns the index of the last element in the list whose value equals val. If no element in the list equals val, this method returns nil.

lastIndexWhich(cond) returns the index of the last element in the list for which the callback function cond returns a non-false value (anything except nil or 0). This method is similar to indexWhich(cond), but scans the list in reverse order, starting at the last element and working towards the first. Returns nil if the callback returns nil or 0 for every element.

lastValWhich(cond) returns the value of the last element in the list for which the callback function cond returns a non-false value. This method is similar to lastIndexWhich(cond), but returns the value of the matching element rather than its index. Returns nil if the callback returns nil or 0 for every element.

length() returns the number of elements in the list.

mapAll(func) for each element of the list, this method invokes the callback function func, passing the current element as the single argument, then adds the return value to a new list. The method returns the resulting new list, which has the same number of elements as the original list. Each element of the returned list contains the result returned by func for the corresponding element of the original list. This method does not modify the original list, but creates a new list.

Here's an example that creates a new list consisting of multiplying each element of an original list by 2 (naturally, for this to work, the original list must consist entirely of integer values):

      x = [1, 2, 3, 4];

      y = x.applyAll({x: x*2});

prepend(val) returns a new list which results from inserting the value val before the first element of the existing list. This method is similar to append(val), but this method inserts the new element at the beginning of the list rather than at the end. Note that if val is a list, it is prepended as a single list-valued element.

removeElementAt(index) returns a new list which results from deleting the element at the given index. For example, [100, 200, 300].removeElementAt(2) yields [100, 300]. The index value must be at least 1 and at most the number of elements in the list; if index is outside this range, the method throws an index out of range exception.

removeRange(startIndex, endIndex) returns a new list which results from deleting the elements starting at startIndex and ending with (and including) endIndex. If endIndex equals startIndex, only one value is deleted, so removeRange(x, x) is equivalent to removeElementAt(x).

Both index values startIndex and endIndex must be at least 1 and at most the number of elements in the list, and endIndex must be greater than or equal to startIndex; the method throws an index out of range exception if these conditions are not met.

sort(descending?, comparisonFunction?) returns a new list consisting of the elements of this list rearranged into a sorted order. By default, this method sorts the elements of the list into ascending order, but you can reverse this ordering by specifying true for the descending argument.

The optional comparisonFunction can be used to specify the ordering of the result. If this argument is not specified (or is nil), the method will sort the elements according to the standard system ordering of values; hence, the elements must be of comparable types (such as all integers or all strings). By specifying a comparison function, you can provide your own special ordering, and you can also sort values that have no system-defined order, such as object values.

If provided, the comparisonFunction value is a pointer to a function taking two arguments, which are two values from the list to be compared. The function returns an integer less than zero if the first value is less than the first, zero if the two values are equal, or an integer greater than zero if the first value is greater than the second.

For example, if you wanted to sort a list of objects so that the objects are placed into descending order of their "priority" property values, where the "priority" property has an integer value, you could do this:

      lst = [obj1, obj2, obj3];

      sortedLst = lst.sort(true, { a, b: a.priority  b.priority });

sublist(start, length?) creates and returns a new list consisting of a sublist of this list starting at the element of this list at index start, and continuing for the number of elements given by length, if present, or to the end of this list if not. Examples:

      [1, 2, 3].sublist(2) yields [2, 3]

      [1, 2, 3].sublist(2, 1) yields [2]

subset(func) creates and returns a new list containing the elements of this list for which the callback function func returns true (i.e., any value other than nil or the integer value 0). For each element of the source list, this method invokes the callback function, passing the value of the current element as the callback function's single argument. If the callback returns nil or the integer value 0, the method omits the element from the result; otherwise, the method includes the element in the result list. The new list's elements will be in the same order as the selected elements from the source list.

This method does not modify the original list.

This example uses a short-form anonymous function to create a new list that contains only the elements from an original list whose values are greater than 10.

      x = [5, 10, 15, 20];

      y = x.subset({x: x > 10});

valWhich(cond) returns the value of the first element for which the callback function cond returns non-false (i.e., anything except nil or 0). This method is similar to indexWhich(cond), but returns the value of the first matching element rather than its index. If cond returns nil or 0 for every element of the list, this method returns nil.