Types
Reference vs value semantics
Which types are shared when assigned or passed (class instances) and which are copied (primitives, structs, arrays).
since 0.1.0-alpha.1linuxwindowswasm
Description
A type is either a reference type or a value type, and that decides what an assignment or a function call does with it.
- Instances of a
classare references. Assigning one to another variable, or passing it to a function, shares the same object. A change made through either name is visible through the other. - Primitives,
structvalues and arrays are values. Assigning or passing one makes an independent copy. A change to the copy does not affect the original.
Sharing versus copying
class Counter {
int n = 0;
}
struct Point {
int x = 0;
int y = 0;
}
void bumpClass(Counter c) { c.n = c.n + 1; }
void bumpInt(int n) { n = n + 1; }
void movePoint(Point p) { p.x = 99; }
Counter c1 = Counter();
Counter c2 = c1;
c2.n = 5;
bumpClass(c1);
console.writeln(c1.n);
int a = 1;
bumpInt(a);
console.writeln(a);
Point p1 = Point(1, 2);
Point p2 = p1;
p2.x = 10;
movePoint(p1);
console.writeln(p1.x);
6
1
1
Rules
- A class instance is shared by every variable, field, parameter and collection slot that refers to it.
- A primitive (
int,float,bool,char,stringand the sized numeric types) is copied on assignment and when passed. - A
structis copied on assignment, on passing as an argument and when read out of a collection. Mutating the copy leaves the original unchanged. - An array is a value:
Array<int> ys = xs;makesysan independent array, soys[0] = 99;does not changexs. Methods such asaddreturn a new array and leave the receiver unchanged. - A copy of a collection is shallow. An array of class instances copies the references, so both arrays still point at the same objects.
- A closure captures an object by reference, so mutations through it are shared. It captures a primitive local by value: the closure works on its own copy, so the enclosing variable never changes.
Examples
Arrays copy; the objects inside them do not:
Arrays are values, their elements may not be
class Counter {
int n = 0;
}
Array<int> xs = [1, 2, 3];
Array<int> ys = xs;
ys[0] = 99;
ys = ys.add(4);
console.writeln(xs[0]);
console.writeln(xs.length());
console.writeln(ys.length());
Array<Counter> list = [Counter()];
Array<Counter> list2 = list;
list2[0].n = 4;
console.writeln(list[0].n);
1
3
4
4
A closure captures an object live but a primitive by value:
What a closure captures
class Box {
int v = 0;
}
void run() {
int seen = 0;
Box box = Box();
() => void inc = () => {
seen = seen + 1;
box.v = box.v + 1;
};
inc();
inc();
console.writeln(seen);
console.writeln(box.v);
}
run();
0
2
Notes
To share mutable state between a closure and its caller, put the state in a small class and capture the instance, not a local int.
See also
- Primitives (the object mask) — The built-in value types, their default values, the methods they carry, and the
voidunit rules.