Next: , Previous: Files, Up: Programming


4.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 read-only when referenced outside the structure, but may be optionally declared public (read-write) or private (read and write allowed 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.