Next: , Previous: Files, Up: Programming


5.7 Structures

Users may also define their own data types as structures, along with user-defined operators, much as in C++. By default, structure members are public (may be read and modified anywhere in the code), but may be optionally declared restricted (readable anywhere but writeable only inside the structure where they are defined) or private (readable and writable only inside the structure). The virtual structure this refers to the enclosing structure. Any code at the top-level scope within the structure is executed on initialization.

A default initializer for a structure S can be defined by creating a function S operator init(). This can be used to initialize each instance of S with new S (which creates a new anonymous instance of S).

struct S {
  public real a=1;
  real f(real a) {return a+this.a;}
}

S operator init() {return new S;}

S s;                            // Initializes s with S operator init();

write(s.f(2));                  // Outputs 3

S operator + (S s1, S s2)
{
  S result;
  result.a=s1.a+s2.a;
  return result;
}

write((s+s).f(0));              // Outputs 2

In the following example, the static function T.T(real x) is a constructor that initializes and returns a new instance of T:

struct T {
  real x;
  static T T(real x) {T t=new T; t.x=x; return t;}
}

T operator init() {return new T;}

T a;
T b=T.T(1);

write(a.x);                     // Outputs 0
write(b.x);                     // Outputs 1
The name of the constructor need not be identical to the name of the structure; for example, see triangle.SAS in geometry.asy.

Structure assignment does a shallow copy; a deep copy requires writing an explicit copy() member. The function bool alias(T,T) checks to see if two instances of the structure T are identical. The boolean operators == and != are by default equivalent to alias and !alias respectively, but may be overwritten for a particular type do a deep comparison.

When a is defined both as a variable and a type, the qualified name a.b refers to the variable instead of the type.

Much like in C++, casting (see Casts) provides for an elegant implementation of structure inheritance, including virtual functions:

struct parent {
  real x=1;
  public void virtual(int) {write (0);}
  void f() {virtual(1);}
}

parent operator init() {return new parent;}
  
void write(parent p) {write(p.x);}
  
struct child {
  parent parent;
  real y=2;
  void virtual(int x) {write (x);}
  parent.virtual=virtual;
  void f()=parent.f;
}

parent operator cast(child child) {return child.parent;}
  
child operator init() {return new child;}

parent p;
child c;

write(c);                       // Outputs 1;

p.f();                          // Outputs 0;
c.f();                          // Outputs 1;

write(c.parent.x);              // Outputs 1;
write(c.y);                     // Outputs 2;

Further examples of structures are Legend and picture in the Asymptote base module plain.