Copying and Mutation
Which ELPS functions change a value in place, when two names share one value, and when to copy.
Lists, vectors and sorted maps are references. When you bind a value to a second name, or take part of it with slice, cdr or rest, both names share the same elements. A function that changes a value in place changes it for every name that shares it.
Every example on this page runs in your browser. Edit an example to see the new result.
Functions that change a value
A function whose name ends in ! changes its argument. The function without ! returns a new value and leaves the argument as it was.
| Returns a new value | Changes its argument |
|---|---|
append, append-bytes |
append!, append-bytes! |
assoc, dissoc |
assoc!, dissoc! |
concat, insert-index, reverse, map, select |
stable-sort |
stable-sort is the one exception to the rule: it has no !, but it sorts in place.
Views share elements
slice, cdr and rest return a view. A change to an element of the view changes the source too. Adding to a view never changes the source.
To get a value that nothing else can change, copy it. copy makes a deep copy. concat copies one level.
Do not change a quoted literal
A quoted value, such as '(3 1 2), is part of the program text. A change to it would change the program, so ELPS refuses it with modify-literal-error. Build the value with list or vector, or copy the literal first.
What copy does not copy
copy does not copy a function. A function keeps the variables it was made with, so a copy of a map of functions still changes the original. To get a new object, call its constructor again, or use a record type.
Sort and map functions must not change values
stable-sort calls its compare function an unknown number of times, in an unknown order, with the list's own elements. A compare function must only compare. The same rule applies to the functions you give to map, select, foldl and the other functions that walk a sequence: do not change the sequence they walk.
;; Wrong: changes each element while it sorts
(stable-sort (lambda (a b) (assoc! a "seen" true) (< (get a "n") (get b "n"))) rows)
;; Right: only compares
(stable-sort (lambda (a b) (< (get a "n") (get b "n"))) rows)
The lint checks comparator-mutation and iteration-mutation report these mistakes.