Words in italics indicate an instance of a class. The word corresponds to the class name, except where more than one instance is represented in the same statement. In that case a number (2, 3, etc.) is appended to the class name.
Words in normal typeface are to be taken literally (required punctuation, class name in a static reference, method name, etc.)
The symbol => is used to separate an expression (on the left) from its return value (on the right).
An ellipsis (...) indicates that the previous argument may be repeated any number of times. The description will indicate whether one instance is required.
Generally speaking, methods that end in "$" modify the receiver, while methods that don't end in "$" are free of side-effects. But that isn't always the case. The methods push and pop (as well as the properties car and cdr when set) modify the receiver -- but I have omitted the "$" because their traditional names adequately communicate their side-effects, I believe.
ls.append(object) => ls2
ls + object => ls2
ls.append$(object) => ls
ls | object => ls
ls.add$(object) => ls
ls & object => ls
ls.appendflat$(object) => ls
The append method (and the + operator) adds an object to a list, returning
a new list. if object is an ArrayList (or a derived class, such as another ls),
then all of its members are added instead of the ArrayList itself.
The append$ method (and the | operator) modifies ls by adding the
object in place, and returns the modified list. It also expands any Arraylist passed.
The add$ method (and the & operator) operates like append$,
but ArrayLists are not expanded. This provides for composing nested lists.
The appendflat$ method operates like append$, but any ArrayList
argument is completely flattened. Not only is the Arraylist replaced by its members, but any
members of the ArrayList that are ArrayLists are recursively expanded.
In all of the above, if object is a primitive, it will be automatically boxed in a Var
.
ls.of(1) | 2 | "fred" | an_object | a_list
Creates a one-dimensional list from three primitives (which are boxed as Vars), an object, and the members of another list
ls.of("1a") & "1b" &
& (ls.of("2a") &
& (ls.of("3a") & "3b"))
Creates a tree with three top nodes: "1a", "1b", and another list that contains two nodes: "2a" and another list that contains two nodes: "3a" and "3b". Note that the ampersands on the left side are Synergy/DE line-continuation characters.
Why didn't I use "<<" for append, and reserve "|" and "&" for union and intersection, respectively? Synergy/DE does not provide an override for "<<". I didn't want to use just "<" in case I add comparison operators later, and intersection and union seem like rare enough operations that requiring them to be spelled out should not be onerous.
ls.car => object
ls.car = object
ls.cdr => ls
ls.cdr = ls2
ls.chop(int) => ls2
ls.chop$(int) => ls
chop method returns a truncated copy of the
original list, leaving the original unmodified, while chop$ modifies and returns the
original list.
ls.compact() => ls2
ls.compact$() => ls
compact$ method modifies and
returns the original list, while compact returns a modified shallow copy, leaving the original
untouched.
ls.contains(object) => boolean
ls.copy() => ls2
ls.countif(mapboolean) => int
test method, return true. See MapBoolean.
ls.empty() => ls
new ls() is not valid in all contexts where the result of a method can
be used instead.
ls.Equals(object) => boolean
ls.flatten() => ls2
ls.from(arraylist) => ls
ls.from(array) => ls
ls.from(realarray) => ls *** Synergy/DE 9.3 and above ***
Creates a new ls from arraylist or array. Members are copied by reference.
For array, up to 3 dimensions are supported for dynamic object arays ([#,#,#]@class), and those dimensions will be preserved as lists within lists. Note that no automatic type conversions will occur. In particular, strings are not converted to VarAlpha. Use the map method to perform these conversions, if desired. For instance, to convert a multi-dimensioned array of strings to a list of lists of VarAlpha:
ls.from(array).map(new MapDeep(new MapAlpha()))
Real arrays of primitive types ([*]type) only work on Synergy/DE version 9.3 and above, due to a compiler bug (tr#30719). If you try to use real arrays with this method in Synergy/DE version 9.1* or even in the 9.2.1 beta, it will crash the Synergy/DE runtime. This method only supports real arrays of one dimension, because I got tired of fighting with the compiler. The primitive values will be boxed as Vars.
Note also that since arrays are 1-based while ArrayLists are 0-based, the indices of members in the resulting list will be one less than their indices in the original array. That goes for both array and realarray
ls.issubsetof(ls2) => boolean
ls.issupersetof(arraylist) => boolean
ls.join(string) => string2
ls.keyadd(object, object2) => ls
ls.keydel(object) => ls
ls.keyfind(object) => ls2
ls.keyget(object) => object2
ls[object] => object2
ls.keygetl(object) => ls
ls.keyset(object, object2) => ls
ls[object] = object2
ls.intersection(arraylist) => ls2
ls.of(object) => ls
ls.map(mapobject) => ls2
ls.map$(mapobject) => ls
map method. The ls method map produces
a new list, while map$ replaces each item in the original list. See
MapObject.
ls.merge(arraylist, compare) => ls2
ls.merge$(arraylist, compare) => ls
Assumes that both lists are sorted, and returns a merged list. The two methods use
different algorithms, with merge$ inserting items from arraylist into ls,
while merge appends items from each list to the new ls2. Method mergesort
uses the merge, which performs slightly better with large lists.
Comparisons between the members of the two lists are performed by calling the test
method of compare. See Compare functors.
ls.mergesort(compare) => ls2
ls.pop() => object
ls.push(object) => ls
ls.quicksort(compare) => ls2
ls.quicksort$(compare) => ls
quicksort copies the list first,
while quicksort$ modifies ls. QuickSort appears from testing to be faster
than MergeSort when the list contains fewer than circa 900,000 elements.
ls.remove(object) => ls2
ls.remove$(object) => ls
ls - object => ls2
remove and the operator -), or the modified receiver (in the case
of remove$). If object is not a member of ls, no error occurs.
if object is primitive, it will be boxed in a Var so that Var comparisons will apply.
See subtract for a method to remove
all elements of one list from another.
ls.removeif(mapboolean) => ls2
ls.removeif$(mapboolean) => ls
removeif leaves ls
unmodified, while removeif$ modifies and returns ls.
ls.reverse() => ls2
ls.rotate$(int...) => ls
ls.sort(compare) => ls2
ls.sort$(compare) => ls
sort$ uses QuickSort to
sort the list in-place, while sort creates a sorted copy of the list. For
sort, if the number of elements in the list is less than 900,000, then QuickSort is
applied to a copy of the list. If 900,000 or above, MergeSort is used instead.
ls.subseq(int) => ls2
ls.subseq(int, int2) => ls2
ls.subtract(arraylist) => ls2
ls.subtract$(arraylist) => ls
ls - arraylist => ls2
subtract and the operator -, the ls is unmodified and a new
list is returned -- while subtract$ modifies and returns its receiver.
If an element in arraylist does not occur in ls, no error occurs.
See remove for removing objects from a list.
ls.ToString() => string
ls.union(arraylist) => ls2
ls.union$(arraylist) => ls
ls.union(object) => ls2
ls.union$(object) => ls
union method returns a new list, while union$ modifies the receiver.
Unlike append, any element found in both lists
is not duplicated. You can therefore use this method to add objects uniquely, as in a set.
Because of the implementation of
ls.Equals(), elements that are instances of ls and contain the same members will be
treated as identical.
ls.uniq() => ls2
ls.uniq$() => ls
uniq method returns a uniq'd copy of the list, while uniq$ modifies
and returns the original list.
The abstract class Compare provides a pattern for functors used in comparisons. It's a poor man's excuse for lambdas, and about the only way to provide a lazy callback that can handle objects in Synergy/DE.
Derived classes must implement one method: test, which takes two object arguments and returns an integer. If the first object is greater than the second, return 1. If equal, return 0, If less than, return -1. The method must be able to handle null objects.
Derived classes may implement other members as needed. For instance, a number of the provided classes (detailed below) implement constructors that take parameters to control their behavior.
Some Compare classes take a Compare as an argument. These are intended to modify the comparison
operation in some way. For instance, to compare objects as lists of strings in descending order, you
could create a combined functor like: new CompareDesc(new CompareList(new CompareString())).
CompareDesc will reverse the sense of the return value from CompareList, which will call CompareString
to compare each member of the lists contained within the list. A good combination to use for sorting
an associative list by key value (if the keys are strings) would be new CompareCar(new CompareVarAlpha())
.
Compare functors also provide overloads for the comparison operators (==, !=, >, <, >=, and
<=), each of which produce a MapBoolean object that performs the specified lazy comparison against the
right-hand term (MapCompareEqual, MapCompareNotEqual, MapCompareGreaterThan, MapCompareLessThan,
MapCompareGreaterThanOrEqual, MapCompareLessThanOrEqual). See MapBoolean.
If the right-hand term is primitive, it will be automatically boxed as a
Var. Thus, for example, to create a lazy evaluation
functor for testing Vars as greater than 5, use new CompareVar() > 5, which
produces a MapBoolean that performs that test against the object passed to its test method.
The following derived classes are provided:
new CompareCar(compare)
If either of the objects is a list, its first element will be used -- otherwise the object itself. If that first element is a list, its first element will be used, and so on recursively until a non-list is encountered. Then the result returned from invoking compare's test method for those two objects will be returned.
This Comparer is useful for sorting associative lists by key. An associative list (or alist) is one in which each element is itself a list, comprised of a key and data. See keyfind.
new CompareDesc(compare)
new CompareList(compare)
new CompareMap1(mapobject, compare)
countif or removeif.
new CompareMap2(mapobject, compare)
new CompareString()
new CompareString(boolean, boolean2)
TestNatural(string, string2) => int
Compares the result of ToString() on both objects. ^null is considered equal to "".
When the constructor is invoked without arguments, defaults to case-insensitive, natural order. If called with arguments, boolean is true for case-sensitive, boolean2 is true for natural order or false for alphanumeric order.
This class also provides the static method TestNatural that compares two
strings according to natural order rules.
new CompareVar()
new CompareVarAlpha()
new CompareVarDec()
new CompareVarInt()
new MapAssoc(ls)
new MapDeep(mapobject)
Recursively maps all sublists using mapobject.
For each object passed to this mapper's map method, if that object is not an
ls, the result is the result of mapping that object using mapobject's map method.
If the object is an ls, then the result is a new ls containing the
results of mapping each of the original members of that sublist using MapDeep and mapobject.
This mapper if useful for mapping only the leaf nodes in a tree, where branches are represented by lists within lists
.
new MapIf(mapboolean, object)
new MapIf(mapboolean, object, object2)
new MapKey(mapobject)
new MapVar()
Treats each object as a Var. Non-Vars are returned as-is. This class is most useful for its derived classes and the operators it provides, which create derived class instances to perform lazy operations on each mapped object.
For instance, new MapVar() + 12 creates a MapVarAdd object (derived from MapVar)
that will add 12 to each object being mapped. MapVar provides
operations for addition, subtraction, multiplication, division, and unary negation.
If either operand in an expression is a MapVar, it will be passed the object to map until a non-MapVar
is returned. Thus it is possible to substitute the object being mapped at multiple points
in a mathematical operation. For instance,
integer(100) - integer(100) / new MapInt() * new MapInt() provides a poor man's
modulo function (100 mod x, where x is the object being mapped) -- at least, until I add
modulo to Var and MapVar.
Some derived classes of MapVar may be instantiated directly:
new MapAlpha()
new MapAlpha(case)
new MapDec()
new MapInt()
MapBoolean maps an object to a boolean value. Derived classes must override method test, which takes an object as argument and returns a boolean.
MapBoolean includes operator overloads for .and. (&&), .or. (||) and .xor. comparisons against other MapBooleans, each yielding a new MapBoolean that combines the two lazy tests (MapAnd, MapOr, and MapXor, respectively). Synergy/DE optimizations apply -- that is, if the first operation in an .and. yields false, the second operation will not be tested, etc. Grouping with parentheses works as expected. An overload for the .not. operator (!) is also provided, which yields a MapBoolean object that reverses the result of its argument (MapNot).
Most of the provided derived classes are instantiated through the use of operators on either the MapBoolean or Compare classes. But you may create your own derived classes to perform other tests.
The following additional derived classes are provided:
new MapNonNull()
new MapNull()