Go to the first, previous, next, last section, table of contents.

Replacing an Element of a List or String

It often happens that one wants to change just one particular slot of a list or string, which is stored in a variable or a property. This can be done conveniently using an indexed assignment having one of the following forms:

variable[index-expr] = result-expr
object-expr.name[index-expr] = result-expr
object-expr.(name-expr)[index-expr] = result-expr
$name[index-expr] = result-expr

The first form writes into a variable, and the last three forms write into a property. The usual errors (E_TYPE, E_INVIND, E_PROPNF and E_PERM for lack of read/write permission on the property) may be raised, just as in reading and writing any object property; see the discussion of object property expressions below for details. Correspondingly, if variable does not yet have a value (i.e., it has never been assigned to), E_VARNF will be raised.

If index-expr is not an integer, or if the value of variable or the property is not a list or string, E_TYPE is raised. If result-expr is a string, but not of length 1, E_INVARG is raised. Now suppose index-expr evaluates to an integer k. If k is outside the range of the list or string (i.e. smaller than 1 or greater than the length of the list or string), E_RANGE is raised. Otherwise, the actual assignment takes place. For lists, the variable or the property is assigned a new list that is identical to the original one except at the k-th position, where the new list contains the result of result-expr instead. For strings, the variable or the property is assigned a new string that is identical to the original one, except the k-th character is changed to be result-expr.

The assignment expression itself returns the value of result-expr. For the following examples, assume that l initially contains the list {1, 2, 3} and that s initially contains the string "foobar":

l[5] = 3          error-->   E_RANGE
l["first"] = 4    error-->   E_TYPE
s[3] = "baz"      error-->   E_INVARG
l[2] = l[2] + 3   =>   5
l                 =>   {1, 5, 3}
l[2] = "foo"      =>   "foo"
l                 =>   {1, "foo", 3}
s[2] = "u"        =>   "u"
s                 =>   "fuobar"
s[$] = "z"        =>   "z"
s                 =>   "fuobaz"

Note that the $ expression may also be used in indexed assignments with the same meaning as before.

Fine point: After an indexed assignment, the variable or property contains a new list or string, a copy of the original list in all but the k-th place, where it contains a new value. In programming-language jargon, the original list is not mutated, and there is no aliasing. (Indeed, no MOO value is mutable and no aliasing ever occurs.)

In the list case, indexed assignment can be nested to many levels, to work on nested lists. Assume that l initially contains the list

{{1, 2, 3}, {4, 5, 6}, "foo"}

in the following examples:

l[7] = 4             error-->   E_RANGE
l[1][8] = 35         error-->   E_RANGE
l[3][2] = 7          error-->   E_TYPE
l[1][1][1] = 3       error-->   E_TYPE
l[2][2] = -l[2][2]   =>   -5
l                    =>   {{1, 2, 3}, {4, -5, 6}, "foo"}
l[2] = "bar"         =>   "bar"
l                    =>   {{1, 2, 3}, "bar", "foo"}
l[2][$] = "z"        =>   "z"
l                    =>   {{1, 2, 3}, "baz", "foo"}

The first two examples raise E_RANGE because 7 is out of the range of l and 8 is out of the range of l[1]. The next two examples raise E_TYPE because l[3] and l[1][1] are not lists.


Go to the first, previous, next, last section, table of contents.