The remaining syntax for expressions is
expression: binary-expression lvalue-expression assignment-operator expression ( lvalue-expression-list ) = expression send-expression declare-expression load-expression assignment-operator: one of = &= |= ^= <<= >>= += -= *= /= %=
lvalue-expression: identifier nil term [ expression ] term [ expression : ] term . identifier ( lvalue-expression-list ) * monadic-expression lvalue-expression-list: lvalue lvalue-expression-list , lvalue
In general, the types of the left and right operands must be the same; this type must be a data type. The value of an assignment is its new left operand. All the assignment operators associate right-to-left.
In the ordinary assignment with =, the value of the right side is assigned to the object on the left. For simple assignment only, the left operand may be a parenthesized list of lvalues and the right operand either a tuple or an adt whose data members correspond in number and type to the lvalues in the list. The members of the tuple, or the data members of the adt, are assigned in sequence to lvalues in the list. For example,
p: Point; x, y: int; (x, y) = p;
If the left operand of a simple assignment is an adt and the right side is a tuple, then the assignment assigns the members of the tuple to the adt data members; these must correspond in number and type with the members of the tuple.
The constant nil may be assigned to an lvalue of any reference type. This lvalue will compare equal to nil until it is subsequently reassigned. In the Inferno implementation of Limbo, such an assignment also triggers the removal of the object referred to unless other references to it remain.
The left operand of an assignment may be the constant nil to indicate that a value is discarded. This applies in particular to any of the lvalues in a tuple appearing on the left; to extend the examples above,
(x, nil) = p;
A special consideration applies to strings. If an int containing a Unicode character is assigned to a subscripted string, the subscript is normally required to lie within the string. As a special case, the subscript's value may be equal to the length of the string (that is, just beyond its end); in this case, the character is appended to the string, and the string's length increases by 1.
A final special case applies to array slices in the form e1[e2:]. Such expressions may lie on the left of =. The right side must be an array of the same type as e1, and its length must be less than or equal to (len e1)-e2. In this case, the elements in the array on the right replace the elements of e1 starting at position e2. The length of the array is unchanged.
A compound assignment with op= is interpreted in terms of the plain assignment;
e1 op= e2;
e1 = (e1) op (e2);
A send-expression takes the form
send-expression: lvalue-expression <- = expression
e1 <- = e2
A declare-expression is an assignment that also declares identifiers on its left:
declare-expression: lvalue-expression := expression
The value and type of a declare-expression are the same as those of the expression.
A load-expression has the form
load-expression: load identifier expression
Execution of load brings the file containing the module into local memory and dynamically type-checks its interface: the run-time system ascertains that the declarations exported by the module are compatible with the module declaration visible in the scope of the load operator (see §11.2). In the scope of a module declaration, the types and constants exported by the module may be referred to without a handle, but the functions and data exported by the module (directly at its top level, or within its adt) may be called only using a valid handle acquired by the load operator.
The value of load is nil if the attempt to load fails, either because the file containing the module can not be found, or because the found module does not export the specified interface.
Each evaluation of load creates a separate instance of the specified module; it does not share data with any other instance.