The Sway Reference Manual/Assignment
Once a variable has been declared, it is possible to change its binding using the assignment operator. Consider the following interaction with the interpreter:
sway> var BLACK = 1; //initialization! INTEGER: 1 sway> var BROWN = 2; INTEGER: 2 sway> var GREEN = 3; INTEGER: 3 sway> var eyeColor = BLACK; INTEGER: 1 sway> eyeColor; INTEGER: 1 sway> eyeColor = GREEN; //assignment! INTEGER: 3 sway> eyeColor == BROWN; //equality? SYMBOL: :false sway> eyeColor == GREEN; SYMBOL: :true
The operator/variable = (equals sign) is bound to the assignment function. The assignment function, however, is not a true function, like those bound to + and *. Recall that + and the like evaluate the things on either side (recall that those things on either side are generically known as operands) before combining them. For =, the left operand is not evaluated (if it were, the assignment
eyeColor = GREEN
would attempt to change the meaning of 1 to be 3). In general, an operator which does not evaluate all its arguments is known as a special form[1].
Now we can see a variable definition has two steps. In the first step, the variable is created and in the second step, a value is assigned to that variable.
The last two expressions given to the interpreter in the previous interaction refer to the == (equality) operator. The operator == returns true if its operands refer to the same thing and false otherwise. In the interaction above, the variables BLACK, GREEN, and BROWN are not meant to change from their initial values. We denote variables whose values aren't supposed to change by naming the variable using (mostly) capital letters (this convention is borrowed from earlier programming languages). The use of caps emphasizes the constant nature of the (not too) variable.
In the above interaction with the interpreter, we use the integers 1, 2, and 3 to represent the colors black, brown, and green. By abstracting 1, 2, and 3 and giving them meaningful names (i.e., BLACK, BROWN, and GREEN) we find it easy to read code that assigns and tests eye color. We do this because it is difficult to remember which integer is assigned to which color. Without the variables BLACK, BROWN, and GREEN, we have to keep little notes somewhere to remind ourselves what's what. Here is an equivalent interaction with the interpreter without the use of the variables BLACK, GREEN, and BROWN.
sway> var eyeColor = 1; INTEGER: 1 sway> eyeColor; INTEGER: 1 sway> eyeColor = 3; INTEGER: 3 sway> eyeColor == 2; SYMBOL: :false sway> eyeColor == 3; SYMBOL: :true
In this interaction, the meaning of the test eyeColor == 3 is not so obvious.
Another approach to constants is to use symbols. Since Sway has symbols as primitives, we can dispense with the constant-like variables and the integers altogether:
sway> var eyeColor = :black; SYMBOL: :black sway> eyeColor; SYMBOL: :black sway> eyeColor = :green; SYMBOL: :green sway> eyeColor == :brown; SYMBOL: :false sway> eyeColor == :green; SYMBOL: :true
sway> println("eye color is ",eyeColor); eye color is green SYMBOL: :green
Note how much more readable this version of the interaction is. Also note that symbols, when printed, are printed without the colon.
Precedence and Associativity of Assignment
[edit | edit source]Assignment has the lowest precedence among the binary operators. It is also right associative. The right associativity allows for statements like
a = b = c = d = 0;
which conveniently assigns a zero to four variables at once and is equivalent to:
(a = (b = (c = (d = 0))));
because of the right associative nature of the operator. Since the resulting value of the assignment operation is the value assigned, this statement works as desired.
How it works
[edit | edit source]Sway takes a novel approach to assignment. Every time a value is retrieved, its address is (usually) saved in an internal register. The assignment operator takes advantage of this fact by:
- looking up the value of the left-hand-side
- checking for a valid address in the internal register
- writing the value of the right hand side to the valid address
For example, the assignment
x = 3;
proceeds by looking up the value of x. The current value of x is ignored, but the internal register now contains the location of x. The value of 3 is then copied to the address and x has a new value.
By this method, one can write to array and list elements as well as objects:
a[y] = z; head(tail(items)) = :green; a . f() . b = "hello";
There are some limitations to assignment. For example, you cannot use the assignment operator to change the tail of a list. For example, this attempt will fail:
tail(items) = list(a,b,c);
because the tail of a list does not have not a normal address in Sway. To change the tail of the list, one uses the tail= operator, instead:
items tail= list(a,b,c);
or
tail=(items,list(a,b,c));
if you prefer function call syntax.
There is a head= operator for changing the head of the list, but it is bound to the regular assignment operator, so you can use either.
Assigning to Thunks
[edit | edit source]If the code in a thunk has a regular Sway address, you can use the assignment operator to update the value at that address. This is how a forEach function would work:
function forEach($target,items,$body) { while (items != null) { $target = head(items); force($body); items = tail(items); } }
Here, the thunk $target is repeatedly updated with the (new) head of the list. Once the update is made with the assignment operator, the body of the forEach is forced and the process repeated. The forEach function can be called with a simple variable, as in
var i; forEach(i,range(0,4)) { println("i is ",i); }
or with an array or list location, as in
var i = array(1,2,3); forEach(i[2],range(0,4)) { println("i[2] is ",i[2]); }
or with an object member, as in
function bundle(a,b) { this; } var i = bundle(1,2); forEach(i . a,range(0,4)) { println("i . a is ",i . a); }
Footnotes
[edit | edit source]- ↑ Unlike most languages, Sway allows user defined special forms.