Arrays (and, in fact, most container classes) are realized using parametrized classes in Sather. There is language support for the main array class ARRAY{T} in the form of a literal expressions of the form
a:ARRAY{INT} := |1,2,3|; |
In addition to the standard accessing function, arrays provide many operations, ranging from trivial routines that return the size of the array to routines that will sort arbitrary arrays. See the array class in the container library for more details. There are several aspects to supporting arrays:
Support for accessing array elements
Support for objects which represent arrays
Support for initializing these arrays using literals
The form 'a[4]:=..' is syntactic sugar for a call of a routine named aset' with the array index expressions and the right hand side of the assignment as arguments. In the class TRIO below we have three elements which can be accessed using array notation
class TRIO is private attr a,b,c:FLT; create:SAME is return new end; aget(i:INT):FLT is case i when 0 then return a when 1 then return b when 2 then return c else raise "Bad array index!\n"; end; end; aset(i:INT, val:FLT) is case i when 0 then a := val; when 1 then b := val; when 2 then c := val; end; end; end; |
The array notation can then be used with objects of type TRIO
trio:TRIO := #TRIO; -- Calls TRIO::create trio[2] := 1; #OUT + trio[2]; -- Prints out 1 |
See unnamedlink for more details on the section on operator redefinition.
Sather permits the user to define array classes which support an array portion whose size is determined when the array is created. An object can have an array portion by including AREF{T}.
class POLYGON is private include AREF{POINT} aget->private old_aget, aset->private old_aset; -- Rename aget and aset create(n_points:INT):SAME is -- Create a new polygon with a 'n_points' points res:SAME := new(n_points); -- Note that the new takes -- as argument of the size of the array end; aget(i:INT):POINT is if i > asize then raise "Not enough polygon points!" end; return old_aget(i); end; aset(i:INT, val:POINT) is if i > asize then raise "Not enough polygon points!" end; old_aset(i,val); end; end; |
Since AREF{T} already defines 'aget' and 'aset' to do the right thing, we can provide wrappers around these routines to, for instance, provide an additional warning message. The above example makes use of the POINT class from unnamedlink. We could have also used the PAIR class defined on unnamedlink. The following example uses the polygon class to define a triangle.
poly:POLYGON := #POLYGON(3); poly[0] := #POINT(3,4); poly[1] := #POINT(5,6); poly[2] := #POINT(0,0); |
AREF defines several useful routines:
asize:INT -- Returns the size of the array aelt!:T; -- Yields successive array elements aelt!(once beg:INT):T; -- Yields elements from index 'beg' aelt!(once beg,once num:INT):T; -- Yields 'num' elts from index 'beg' aelt!(once beg,once num,once step:INT):T; -- Yields 'num' elements, starting at index 'beg' with a 'step' ... Analgous versions of aset! .. acopy(src:SAME); -- Copy what fits from 'src' to self acopy(beg:INT,src:SAME); -- Start copying into index 'beg' acopy(beg:INT,num:INT,src:SAME); -- Copy 'num' elements into self starting at index 'beg' of self aind!:INT; -- Yields successive array indices |
When possible, use the above iterators since they are built-in and can be more efficient than other iterators.
The class ARRAY{T} in the standard library is not a primitive data type. It is based on a built-in class AREF{T} which provides objects with an array portion. ARRAY obtains this functionality using an include, but chooses to modify the visibility of some of the methods. It also defines additional methods such a contains, sort etc. The methods aget, aset and asize are defined as private in AREF, but ARRAY redefines them to be public.
class ARRAY{T} is private include AREF{T} -- Make these public. aget->aget, aset->aset, asize->asize; ... contains(e:T):BOOL is ... end ... end; |
The array portion appears if there is an include path from the type to AREF for reference types or to AVAL for immutable types.
Sather provides support for directly creating arrays from literal expressions
a:ARRAY{INT} := |2,4,6,8|; b:ARRAY{STR} := |"apple","orange"|; |
.
The type is taken to be the declared type of the context in which it appears and it must be ARRAY{T} for some type T. An array creation expression may not appear
as the right hand side of a '::=' assignment
as a method argument in which the overloading resolution is ambiguous
as the left argument of the dot '.' operator.
a:INT := |1,2,3|.size -- ILLEGAL |
The types of each expression in the array literal must be subtypes of T. The size of the created array is equal to the number of specified expressions. The expressions in the literal are evaluated left to right and the results are assigned to successive array elements.
Special support is neither present nor needed for multi-dimensional arrays. The 'aget' and 'aset' routines can take multiple arguments, thus permitting multiple indices. The library does provide ARRAY2 and ARRAY3 classes, which provide the necesary index computation. All standard array classes are addressed in row-major order. However, the MAT class is addressed in column major order for compatibility with external FORTRAN routines[1]. Multi-dimensonal array literals may be expressed by nesting of standard array literals
a:ARRAY{ARRAY{INT}} := ||1,2,3|,|3,4,5|,|5,6,7||; |
[1] Efficiency in converting to FORTRAN was more important for mathematical entitites which will be used with existing mathematical libraries such as BLAS and LAPACK, most of which are in FORTRAN.