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 1The 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
.