Lisp implementations have the advantage that all objects are accessible through some path originating in the symbol tables and the whole accessible structure is an intrinsic part of Lisp. Thus, much of the extra data structure for doing garbage collection in Lisp exists for free and is more cogent than C++ as a starting point for garbage collection algorithms. Since Lpp does not have this structure available under C++ and since there are many reasonably good C++ garbage collection algorithms available, Lpp does not commit to any of these in principle nor provides any kind of automatic garbage collection.
Lpp does provide a facility for doing manual garbage collection much
the same way delete works in standard C++. But it makes the
garbage collection of complex Lpp data structures easier. All Lpp
garbage collection functions only serve to deallocate the storage of
some data and then just return nil.
| gc object | Function |
gc garbage collects the Lpp object object.
Here is a trivial example:
let a = L(1);
let b = L(2);
let c = plus(a, b); // assume c is needed from here on
gc(a); gc(b); // and a and b are not
In general, for predefined Lpp object types the object and all of its
components are collected except for some exceptions listed in the next
paragraph. For user defined Lpp objects gc calls delete
of the specific subtype class for object.
Since Lpp symbols have global import gc will do nothing if
object is a Symbol. Usually you do not want to remove symbols.
However in cases where you absolutely must the proper way to remove
symbols and have them collected is to use unintern which
removes the symbol from the system and garbage collects all of the
associated parts, See Creating Symbols. If gc is called on
a cons it collects the cons object only and not its car
or cdr.
For garbage collecting cons structures gcList should be used
for garbage collecting top level lists and gcTree for
collecting tree structures. In these functions a leaf argument
says what to do with the leaf nodes of a list or a tree. Leaf nodes
are a car or cdr of a cons that is something other than a list
(nil or another cons). However the main difference between
gcList and gcTree is that with gcList the
car of every cons in the top level list is also treated as a
leaf node for the listed meanings below of the leaf argument.
Note that because of this using gcList with a special user
collection function as the leaf argument the user can effectively
create his own special version of gcTree. This also implies
that if the programmer wants to use gcTree on a top level list
that has a cons in some of its cars he should use gcTree
instead or else supply his own leaf function argument to collect such
cars or otherwise take care of them.
The leaf argument can be one of three things with the following implied meanings:
nil => Do not garbage collect leaf nodes
t => Apply gc() to leaf nodes
Function f => Apply Function f to leaf nodes
gcList will handle all lists including circular and dotted
lists. gcTree will handle all trees except trees that have
circular or multiple references. However it will break with an
explanation error message if it detects either circular or multiple
references for most trees. The only cases where it doesn't detect is
where there are circular or multiple reference paths where there are
no leaves in the path. For example
let self = list(True);
rplaca(self, self);
Clearly this simple tree has a circularity with no leaf nodes in the
circular path. This would fail with gcTree. But this is not
usual and is probably not even useful. In such unusual trees the
programmer must either create his own collection function or else
store a non-cons in such a problematical cons slot and then call
gcTree.
| gcList list leaf | Function |
gcList will garbage collect the list list and leaf nodes
depending on the leaf argument as described above. For this
purpose the cars of each cons in the list will always be treated as
leaf nodes even if they contain other cons objects.
Here are some examples.
let list1 = list(L("one"), L("two"), L("three"));
let list2 = copyList(list1);
// leaf argument is nil, so list1 is grabage collected
// but Strings "one", "two", "three" are left alone.
gcList(list1, Nil);
// leaf argument is t, so list2 is grabage collected
// and so are Strings "one", "two", "three"
gcList(list2, True);
list1 = list(myObject1, myObject2);
// leaf argument is the Function myCollector
// so list1 is garbage collected while the function myCollector
// is applied to the leaf node objects myObject1, myObject2
gcList(list1, L(myCollector));
| gcTree tree leaf | Function |
gcTree will garbage collect the tree tree and leaf nodes
depending on the leaf argument as described above. The
tree argument can be a cons or a non-cons Lpp object. If it is
a non-cons object then the leaf argument is applied to the
object.
If there are circular or multiple references in the tree in paths that
have one of more leaves then gcTree will break with an error
message stating such. For any trees with circular or multiple
references the programmer can either store a non-cons in the offending
cons slots and then call gcTree or write a gc function
specialized for such a data structure and call gcList passing
the specialized function as the leaf argument.
Here are some examples using association lists which are in effect small trees:
let alist1 = list(cons(L("one"), L(1)),
cons(L("two"), L(2)),
cons(L("three"), L(3)));
let alist2 = copyAlist(list1);
// leaf argument is nil, so alist1 is grabage collected
// but Strings "one", "two", "three" are left alone
// and numbers 1, 2 and 3 are left alone.
gcTree(alist1, Nil);
// leaf argument is t, so alist2 is grabage collected
// and so are Strings "one", "two", "three"
// and numbers 1, 2 and 3.
gcTree(alist2, True);
alist1 = list(cons(L(1), myObject1),
cons(L(2), myObject2));
// leaf argument is the Function myCollector
// so alist1 is garbage collected while the function myCollector
// is applied to the leaf node objects 1, 2, myObject1, myObject2
gcTree(alist1, L(myCollector));
It is easy to garbage collect raw cons objects and their parts.
For example assume the variable var contains a cons,
then
gcTree(cdr(var)); // Collects just the whole cdr tree of var
gc(var); // Collects just the cons var and not the car or cdr
There are many combinations of ways to collect cons structures
and their parts. But the following function fulfills a common case
| gcConsElement cons | Function |
gcConsElement will
garbage collect the whole car tree of cons using
gcTree and then garbage collect the cons itself. It is
useful for completely collecting ordinary list elements that are
represented by cons structures and is used by some Lpp functions that
optionally perform a garbage collection on destructive list
operations, such as nremove, See Modifying Sequences.