LEVIATHAN v962456e · 962456eee1

Declarations

Fields

Declare the data a class or struct holds, with optional initializers, and how a field without an initializer gets its default value.

since 0.1.0-alpha.1linuxwindowswasm

Description

A field is a named slot of data inside a class or struct:

public string label;
public distinct int value = 0;
int count = 5;

A field has a type and a name, an optional access modifier, optional modifiers (distinct, const, readonly, weak) and an optional initializer. An initializer is an expression that is evaluated each time an object is created, so every object gets its own value, including its own array.

A field or local variable declared without an initializer is constructed with the default for its type. This is why a bare declaration is always safe to read:

type default
int 0
float 0.000000 when printed
bool false
string ""
Array<T>, Map<K, V> empty
T? None
a class or struct an object made with default construction

Defaults and per-object initializers

class Inner { int n = 7; }
class Rec {
    int i;
    float f;
    bool b;
    string s;
    Array<int> a;
    Map<string, int> m;
    Inner inner;
    int? maybe;
    int withInit = 5;
}
Rec r = Rec();
console.writeln(r.i);
console.writeln(r.f);
console.writeln(r.b);
console.writeln("[" + r.s + "]");
console.writeln(r.a.length());
console.writeln(r.m.length());
console.writeln(r.inner.n);
console.writeln(r.maybe);
console.writeln(r.withInit);
int local;
string sl;
console.writeln(local);
console.writeln("[" + sl + "]");
0
0.000000
false
[]
0
0
7
None
5
0
[]

Rules

  • A field declaration is [access] [modifiers] Type name [= initializer];.
  • An initializer runs once for each object created, in declaration order, so a field initialized with an array literal or a call gets a fresh value for every object.
  • A field with no initializer gets its type's default, as in the table above. Fields of class type are constructed with default construction.
  • A field whose type is its own class has no finite default value. Declare it optional (Node? next;); it starts as None.
  • const fixes a field to a compile-time constant (lang.const); readonly fixes it at construction time (lang.readonly); weak makes it a non-owning reference (lang.weak-fields); distinct keeps it separate from a same-named field of another base (lang.distinct).
  • A field redeclared along a single inheritance chain is one slot, and the more-derived declaration wins. Two unrelated bases declaring one name and type is a compile error unless the class restates the field or one of them is distinct. A class holds one field per name: two bases declaring one name with different types is a compile error unless one is distinct; see lang.multiple-inheritance.

Examples

Initializers are evaluated for each object:

Each object evaluates its initializers

int counter = 0;
int next() { counter += 1; return counter; }
class Item {
    int id = next();
    Array<string> tags = [];
    string label = "item-" + counter.toString();
}
Item a = Item();
Item b = Item();
console.writeln(a.id);
console.writeln(b.id);
console.writeln(a.label);
console.writeln(b.label);
a.tags = a.tags.add("x");
console.writeln(a.tags.length());
console.writeln(b.tags.length());
1
2
item-1
item-2
1
0

A link back to the same type is optional:

A self-referential field

class Node { int v = 1; Node? next; }
Node n = Node();
console.writeln(n.next == None);
n.next = Node();
console.writeln(n.next != None);
true
true

See also

  • Classes — Declare reference types with fields, methods, constructors and accessors, with generics and inheritance from one or more base classes.
  • Value structs — Declare value types that are copied on every assignment, pass and return, with derived equality and explicit mutating methods.
  • distinct fields — Keep same-named fields of different bases in separate slots, reached by qualification.
  • const declarations — Fix a local, field, global, parameter or loop binding after its initializer, with the exact rules for each kind of slot.
  • readonly fields — Fix an instance field once, either in its initializer or in every constructor, and keep it read-only afterwards.
  • weak fields — Hold a non-owning reference to an object that reads as None once the object is gone.