LEVIATHAN v962456e · 962456eee1

Declarations

Value structs

Declare value types that are copied on every assignment, pass and return, with derived equality and explicit mutating methods.

since 0.1.0-alpha.1linuxwindowswasm

Description

A struct is a value type. Where a class variable holds a reference to a shared object, a struct variable holds the value itself. A struct is copied every time it is bound to a variable, passed to a function, returned, or stored into an array or another object, and a copy has no connection to the original. Structs have no identity.

struct Point {
    int x;  int y;
    int dot() => x * x + y * y;
    mutating void translate(int dx, int dy) { x = x + dx; y = y + dy; }
}

A method that changes this must be marked mutating; a plain method that assigns a field is a compile error. Constructors and set accessors are mutating by definition. Choose a struct for plain data such as coordinates and rows, and a class for entities with identity. Arrays of structs can be stored densely, which makes them compact and fast to scan; see lang.columnar-arrays.

Structs are copied

struct Point {
    int x;
    int y;
    int dot() => x * x + y * y;
    mutating void translate(int dx, int dy) { x = x + dx; y = y + dy; }
}
Point a = Point(1, 2);
Point b = a;
b.translate(10, 10);
console.writeln(a.x);
console.writeln(b.x);
console.writeln(a.dot());
void bump(Point p) { p.translate(100, 100); }
bump(a);
console.writeln(a.x);
Array<Point> ps = [Point(1, 1), Point(2, 2)];
Point first = ps.at(0);
first.x = 99;
console.writeln(ps.at(0).x);
console.writeln(a == Point(1, 2));
console.writeln(a != b);
1
11
5
1
1
true
true

b is a copy: translating it leaves a untouched. The function bump changes only its own copy, and changing first leaves the array's element alone.

Rules

  • A struct is copied on bind, pass, return and store. The copy is deep for nested structs; a field that holds a reference (a class instance) copies the reference, so the copy and the original share that object.
  • A struct is final: it cannot inherit from a class or another struct and nothing can inherit from it. It may implement interfaces.
  • A method that writes a field of this must be declared mutating. Calling a mutating method through a const binding is a compile error.
  • Constructors and set accessors may write fields without the mutating keyword.
  • A struct has a derived == and != that compares the fields one by one. Fields of struct type are compared field by field in turn, and a field that holds a class instance is compared by identity, so two different objects with equal contents make the structs unequal.
  • Derived equality is available only when every field is comparable. A struct that has an array or map field has no derived ==; define bool (==)(Type other) to compare such a struct.
  • A struct compares by value when used as a Map key or in a Set.

Examples

The copy shares referenced objects, and equality compares references by identity:

Nested structs, shared references, and equality

class Box { int n = 0; }
struct Point { int x; int y; }
struct Line { Point from; Box box; string name; }
Line a = Line(Point(0, 0), Box(), "a");
Line b = a;
b.from.x = 50;
b.box.n = 7;
console.writeln(a.from.x);
console.writeln(b.from.x);
console.writeln(a.box.n);
console.writeln(a == Line(Point(0, 0), Box(), "a"));
console.writeln(a == Line(Point(0, 0), a.box, "a"));
0
50
7
false
true

from is a nested struct, so b has its own copy of it; box is a reference, so both lines share one Box. The first comparison is false because it builds a new Box; the second reuses a.box.

A struct can implement an interface:

A struct implementing an interface

interface IShow { string show(); }
struct Tag : IShow {
    string text;
    string show() => "<" + text + ">";
}
IShow s = Tag("hi");
console.writeln(s.show());
<hi>

Structs cannot be inherited from or inherit implementation:

Structs are final

struct P { int x; }
class Q : P { }          // error: cannot inherit from struct 'P'; value types are final
class B { int x; }
struct S : B { }         // error: struct 'S' cannot inherit implementation
struct M { int x; void bad() { x = 1; } }   // error: mark the method `mutating`
not run — a compile error on purpose

See also

  • Classes — Declare reference types with fields, methods, constructors and accessors, with generics and inheritance from one or more base classes.
  • Fields — Declare the data a class or struct holds, with optional initializers, and how a field without an initializer gets its default value.
  • Interfaces — Declare the members a class must provide, including fields, and let any class satisfy them by declaring those members.
  • Columnar storage of struct arrays — How native builds lay out an array of simple structs column by column, when that applies, and how to turn it off.