[Nickle] About arrays and things

Bart Massey bart at cs.pdx.edu
Mon Jun 30 02:47:49 PDT 2003


This is an attempt to summarize a long talk Keith and I had
about Nickle semantics, esp about arrays.  The following
statements are true as of June 28, 2003.

  + Nickle assignment is by "rebinding with
    copied value".  If I say

      int[3] x = {1,2,3};
      int[3] y = {4,5,6};
      x = y;

    the third line will make the storage location x have a
    fresh copy of the array at storage location y; the old
    x array is not altered by this operation, although it
    can no longer be referenced.

  + The size is not part of the type.  Thus, I can currently
    say

      string[1] a = (string[2]){};
    
    without error: the array dimensions are deleted without
    examining them.  The only time that the array dimensions
    currently matter are in certain kinds of initializations
    such as

      string[3] a = {"x" ...};

    where they are used to determine the size of the
    implicitly allocated fresh array.  The synonym "*"
    can and should be used where size doesn't matter, e.g.

      int f(int[3] a) {
       ...

    is bad style since the 3 in the parameter declaration
    will never be checked.

  + Nickle arrays are fully bounds-checked.

  + Nickle has "const" declarations, that correspond to
    globally-allocated storage that must be initialized in
    its definition.

In the new world as of June 31, several things will have
changed:

  + Array sizes are still not part of their static type:
    they cannot be, since they are not in general statically
    computable.
    
  + Arrays sizes become part of the dynamic type system.
    Thus e.g. the parameter passing example above becomes
    checked.

  + There are two kinds of values of array type: growable
    arrays and fixed arrays.  A growable array has no upper
    bounds check on stores: storing into an "off-the-end"
    location causes that location and all intervening
    locations to suddenly spring into existence.

       int[*] x;
       x[1] = 0;
       assert(dim(x) == 2, "bad dim");
  
    A fixed array is defined using integer subscript or
    the new array operator [...].  Growable arrays are
    defined using the array operator [*] as above.  (Yes,
    this is completely wrong-headed: * should be fixed and
    ... should be variable---bug Keith about fixing it.)

  + Growable arrays can be sized arbitrarily using the
    setdim() and setdims() functions, which are analogous
    to dim()/dims():

       setdim(&x, 2);

  + The sizing expression in an array declaration need not
    be constant.  This brings up some serious issues with
    typedef.  Consider

       {
         int i = 3;
         typedef int[i] t;
	 t a1 = {1,2,3};
	 i = 4;
	 t a2 = {1,2,3,4};
	  ...

    Should this last assignment work or not?  It probably
    depends on whether one views the i in the typedef to be
    bound at type-def time, or at type-use time.  Nickle
    chooses the latter view.  Like Nickle constants, Nickle
    array dimensioning values in typedefs are expressions
    evaluated with global lifetime.  Thus, the last line is
    illegal.

  + Note that for array definitions without typedef, the
    subscript expression is evaluated with the same lifetime
    as the array itself. 

Enough for tonight: more tomorrow.

	Bart



More information about the Nickle mailing list