table of contents
Comp Sci
October 2003

Assignments in San

This 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 revisited

It 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 expressions

San 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[]  = []          <# Vector assignment >
        u[,] = v[,]             <# Table assignment  >
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 Lists

This 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 assignment

There 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 assignment

San 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 operator

Two items of the same dimensionality can be swapped using the swap operator, <->. For example:
        a     <-> b
        foo[] <-> bar[]
        x[,]  <-> y[,]

9.6 Assignment of functions

Executable 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 cloning

Assignment 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 code

In 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.

table of contents
Comp Sci
October 2003