Assignments in SanThis is still another epistle in the ongoing saga of the definition of the San programming language. This article goes into semi-gory details about assignment statements. 9. San language - assignment revisitedIt has occurred to me that there is no need for := for assignment since the only use of the equals sign is in assignment statements. Accordingly I'm going to revert to using the plain = character. San has a variety of forms of assignment statements. The major categories, which are syntactically distinct, are direct assignment, scatter assignment, and folded assignment. Within these categories there are variants depending on the mode of the target and of the assignment expression. San recognizes three basic modes of assignment expression - scalar, vector, and table. 9.1 Dimensioned expressionsSan supports scalar, vector, and table expressions. For the sake of convenience we shall illustrate them using arithmetic expressions. Here is a scalar expression:
x + 1 <# add one scalar value to another>
It says, simply enough, that the value of the expression is the
sum of the scalar value of x and the literal number 1. Vector
and table expressions are more interesting. Here are the two
basic forms of vector expression:
foo[] + 1 <# Add 1 to each component of foo>
foo[] + bar[] <# Add foo[i] and bar[i] foreach i>
When vectors are being combined they must have the same size, In
the example, foo$nrow must equal bar$nrow. If they aren't an
exception, vector-size-error, will be raised. The above forms
are for row veectors; we also form vector expressions using
column vectors. Row and column vectors may be freely intermixed,
provided that sizes are consistent. Thus we can say:
foo[] + bar.[] + 1
Table expressions are analogous. We have:
foo[,] + 1 <# Add 1 to each table element >
foo[,] + bar[,] <# foo[i,j] + bar[i,j] foreach i,j>
Again, when tables are combined they must be compatiable, i.e.,
they must each have the same number of rows and columns. If they
aren't a table-size-error exception is raised.
Tables and vectors can't be mixed in an expression. 9.2 Direct assignment
The basic forms are:
(a) scalar = scalar expression
(b) vector = vector expression
(c) table = table expression
Some examples:
x = y + 1 <# Scalar assignment >
a[] =
In vector assignment the value of $nrow ($ncol for assignment
to column vectors) in the target is adjusted to match the length
of the vector expression being assigned. In table assignment the
row and column vectors are also copied, and $nrow and $ncol are
also set.
We can also assign (the value of) scalar expressions to vectors and tables. In these assignments each element of the target is set to the assigned scalar value. Examples:
a[] = 1 <# Each element of a is set to 1>
u[,] = 0 <# All elements in u are et 0s>
Sequents can also be assigned to vectors via the equals sign.
For example:
a[] = [1...n] <# a is now a vector of length n>
9.3 Direct Assignment to Scalar ListsThis is a specialized form that exists as a matter of convenience. On the left side there is a list of targets, all scalars; on the right side there is either a single scalar expression or a list of scalar expressions with the same length as the list of targets. Here are some examples:
a, b = 0 <# set a and b to 0>
x, y = u, v <# set x=u, y=v>
The implementation is required to behave as though a vector of
temporaries were created corresponding to the targets, then the
values from the right hand side are assigned to the temporaries,
and finally the temporaries are assigned to their corresponding
targets. In particular it is guaranteed that
a, b = b, a
swaps the scalar values of a and b.
9.4 Distributed assignmentThere are two forms of distributed assignment, one in which the contents of a vector are placed one by one into the variables in a list, and the other in which the contents of a list of variables are placed in a vector. The list consists of a list of scalars optionally terminated by a vector. Here are some examples where a vector is being used as a stack:
foo[] -> mean, std-dev, foo[] <# pop vars from a stack>
foo[] <- mean, std-dev, foo[] <# push vars onto a stack>
As a matter of convenience we will use the term pop for the first
form and push for the second. If there are more items in the
source than there are variables in the target list, then the
excess items are not assigned. Conversely, if there are fewer
items in the source than places in the target list, then the
surplus targets are set to the empty string; if there is a
terminal vector, it is set to be an empty vector. For example,
in:
foo[] <- 1, 2
foo[] -> a, b, c, d[]
a is set to 1, b is set to 2, c is set to the empty string, and d
is an empty vector.
Sequents can be used in lieu of vectors as sources. For example, we can say:
blah[] <- [1...n]
[1...n] -> first, second, rest[]
9.5 Folded assignmentSan supports C style folded assignment, e.g,
foo += 1
bar[] *= 2
ax[,] /= handle
u, v -= w
The rules that specify the supported operations are yet to be
determined. The general form is:
target-list op= expression
For each target in the target list we execute
The target list can be mixed if the expression is a scalar. Otherwise the items in the target list must match the dimension of the expression. 9.6 The swap operatorTwo items of the same dimensionality can be swapped using the swap operator, <->. For example:
a <-> b
foo[] <-> bar[]
x[,] <-> y[,]
9.6 Assignment of functionsExecutable elements can be copied (assigned) and swapped in much the same way the same way as scalar values are, with the proviso a function aspect be identified. For example:
foo$sort = sort$f
copies the default function aspect of proc sort into the sort
aspect of proc foo.
9.8 Morph cloningAssignment statements copy values into the data fields and specified aspects of a morph. To do a complete copy (cloning) one must use the set command, to wit:
set foo = bar
Object oriented programming can be encompassed by using cloning
and the object template model in contradistinction to the class
instance model.
9.9 Illustrative codeIn this example we use gaussian elimination to invert a matrix. This is not production code; it does not do maximum pivoting nor does it check that the matrix is square.
begin proc invert-matrix
args: A
n = A$nrow
B$nrow, B$ncol = n
B[,] = 0
begin loop i from [1...n]
B[i,i] = 1
end loop
begin loop i from [1...n]
pivot = A[i,i]
A[i,] /= pivot
B[i,] /= pivot
begin loop j from [1...n | remove i]
factor = A[j,i]
A[j,] -= A[i,] * factor
B[j,] -= B[i,] * factor
end loop
end loop
set A = B
return B
end invert-matrix
Note: In the sequent article, "remove" was given as "rmv-list".
This page was last updated October 24, 2003. |