Cautions on the use of "array" in SCL


This is a note regarding the relationship between arrays and groups in SCL. For certain purposes, arrays and groups are treated interchangably. For example, many SCL constructors will interpret either an array or a group argument as a list. However, there are also real differences between arrays and groups in SCL.

 The executive summary is that an array in SCL is implemented by a light-weight list structure that uses reference semantics. Groups on the other hand should be used to represent geometric or structural decomposition, or where copy semantics are required. For more details keep reading.

Arrays were originally intended as light-weight convenience list structures for SCL. A typical example of this is:

 

        show( array(A,B,C) );


The semantics of array in SCL is that of reference to model
objects.  Hence side effects, such as called for by the "show"
statement above, happen to the referenced models, and not to
the model object that represents the array itself (the array itself
has no display method).  Here's an example where it matters:
    Test : true;

    Q : if ( test )
    {
        A1 : pt(0,0);
        B1 : pt(1,1);
        array( A1, B1 );
    }
    else
    {
        A2 : pt(2,2);
        B2 : pt(3,3);
        array( A2, B2 );
    }

    # The next statement will show A1 and B1 as defined above.
    show( Q );

    # Now change the value of Q via dependency propagation.
    #
    # Note that even though the value of Q will be changed,
    # what is displayed is NOT updated since Q itself is
    # not displayed (only the models referenced are displayed).
    Test : false;

    # The next statement will show A2 and B2 as defined above,
    # BUT A1 and B1 are STILL SHOWN.
    show( Q );



Here's another gotcha to beware of:
    forCollect( I; 0; I <= 1; I+1 )
        forCollect( J; 0; J <= 1; J+1 )
            array( I, J );


Here's the result:
        group
          object #0 = group
            object #0 = array
            {
              [0] = i = 2
              [1] = j = 2
            }
            object #1 = array
            {
              [0] = i = 2
              [1] = j = 2
            }
          end group
          object #1 = group
            object #0 = array
            {
              [0] = i = 2
              [1] = j = 2
            }
            object #1 = array
            {
              [0] = i = 2
              [1] = j = 2
            }
          end group
        end group


Probably not what you had in mind.  Remember that the arrays
constructed in the inner loop use references to the model
objects for I and J.  Changes in the values for I
and J will be reflected in the final result.
You probably want to use "group" instead:

 

    forCollect( I; 0; I <= 1; I+1 )
        forCollect( J; 0; J <= 1; J+1 )
            group( I, J );


Which gives the following result:
        group
          object #0 = group
            object #0 = group
              object #0 = 0
              object #1 = 0
            end group
            object #1 = group
              object #0 = 0
              object #1 = 1
            end group
          end group
          object #1 = group
            object #0 = group
              object #0 = 1
              object #1 = 0
            end group
            object #1 = group
              object #0 = 1
              object #1 = 1
            end group
          end group
        end group


Why is this different than the case for arrays?  Because the semantics
of group is copy rather than reference. (Note that it is still
possible to implement groups using referencing internally.)
Finally, given the following:

 

    procedure foo( Arg1, Arg2 )
    {
        A: Arg1 + Arg2;
        B: Arg1 * Arg2;
        array( A, B );
    }


What will result from the invocation:
    foo( 1, 2 );


The result is the following error reported from SCL:
Model error: User procedure foo returns reference to model
             in procedural scope. Use group instead. (argument 1)


Again, the reason is that the semantics of array is that of reference.
What does it mean to reference a model object, defined in the scope of
a procedure, from outside that procedure?  The answer is that it is
undefined because the next invocation of that procedure (from any
section of the SCL code) will change the value of that model object.
The situation is a bit like returning the pointer to an auto-variable
from a procedure in C++.