Shared types
A shared type has an identity instead of a value, so assigning it never copies, a change of the object needs no var path, isSame compares which object rather than which content, and Equals, Hash and copy are not generated for it.
Diese Seite gibt es noch nicht auf Deutsch, deshalb steht sie hier auf Englisch. Zur englischen Seite
Every ordinary type is a value: assigning it copies it. shared type is the exception, for the few things that
have an identity - a connection, a file, a window - where everybody holding it has to see the same object.
Example#
shared type Connection {
url: String
protected var sent: Int = 0
var fn send(message: String) {
sent = sent + 1
}
}
const connection = Connection "tcp://example.test"
const same = connection // The same object, not a copy
same.send "hello"
print connection.sent // 1Syntax#
shared type <Name> {
<field>
<function>
}Rules#
Assigning a
shared typenever copies it.const same = connectiongivessamethe same objectconnectionnames; a change through one is visible through the other, which is never true of an ordinarytype.A change of an object is not a question of the path it is reached through. An object has one identity and no copy, so its
var fnmembers and itsvarfields change through any binding that holds it: aconstone, a parameter, an element of aconstlist. What still decides is the object's own type - a field that is notvarnever changes, andprotected varis written only by the file of the type.shared type Connection { url: String protected var sent: Int = 0 var fn send(message: String) { sent = sent + 1 } } const connection = Connection "tcp://example.test" const pool = [connection] connection.send "hello" pool[0].send "again" print connection.sentvaron a binding of a shared type means rebinding, and nothing else. Aconstbinding always names the same object, and avarone may be pointed at another. That is also whyselfof a shared type is never replaced: a method changes the object everybody holds, andself = ...- or handingselfto avarparameter - would point the caller's binding somewhere else instead.Kompiliert nichtshared type Connection { url: String var fn reconnect() { self = Connection url } } // error: `self` is the object itself, and a method of a shared type cannot replace itKompiliert nichtshared type Connection { url: String } const connection = Connection "tcp://example.test" connection = Connection "tcp://other.test" print connection.url // error: `connection` is a `const`. Only a `var` binding can be changedEquals,Hashandcopyare not generated for ashared type.==is about content and does not exist for an object;Showis ashared trait, so a shared object can still be printed.isSamecompares identity, and only ashared typehas one. Calling it on an ordinary value is rejected, because the answer would expose whether that value's implementation happens to share storage. A type parameter and a value of ashared traitare rejected too: a value may stand behind either, and the checker cannot tell - the same reasonspawnrefuses them from the other side.Kompiliert nichttype Point { var x: Int var y: Int } const a = Point x: 1, y: 2 const b = Point x: 1, y: 2 print isSame(a, b) // error: `isSame` compares identity, and a `Point` is a valueKompiliert nichtfn same<Value>(first: Value, second: Value): Bool { isSame(first, second) } // error: `isSame` compares identity, and a `Value` may be a valueA
var fnmethod of ashared typemay answer aTask; the same method on a value may not. Avaron a value is "copy in, copy out" that ends when the call returns, so a change made after the call answers would be lost - avar fnmethod that answers aTaskis only sound where there is one object and no copy to lose.Kompiliert nichttype Counter { var count: Int = 0 var fn tick(): Task<Void> { count = count + 1 } } // error: `tick` changes `self` and answers a `Task`, and `Counter` is a valueA shared object stays in the task that made it.
spawntakes only what it can see is a value, so a shared object, a value that holds one, and anything that may hide one - a type parameter, a function value, a value of ashared trait- are refused where the closure captures them (see Tasks, rule 5). A value of an ordinary trait may cross, so it may not hide an object either: a value whose type holds one does not become a value of an ordinary trait that does not show it (Iterate<Counter>shows it, ashared traitis an object itself). The one residue is an object captured by a closure that a trait value holds - a function value holds nothing by its type - and the runtime keeps such a task on the worker that made the object.Kompiliert nichtshared type Counter { var count: Int = 0 } trait Action { fn run(): Int } type Bumper with Action { counter: Counter fn run(): Int { counter.count } } const action: Action = Bumper(Counter()) // error: `Bumper` holds an object, and a value of `Action` would hide itOnly a
shared typeimplementsClose. The destructor belongs to one object, and a value is copied on assignment, so two copies would close one resource twice. The same holds for a trait that comeswith Close, such asSinkandSource(see Destructors).Kompiliert nichttype Ticket with Close { var fn close() {} } // error: `Close` may only be implemented by a `shared type`
What this is not#
A shared type is not the default choice for anything that gets passed around. Almost nothing needs one: a value
copied and passed everywhere is exactly what keeps two bindings from ever aliasing by accident. shared type is for
the few things whose whole point is that everybody sees the same one - a handle to something outside the program.
type Point {
var x: Int
var y: Int
}
var a = Point x: 1, y: 2
var b = a // A copy: changing `b` never changes `a`
b.x = 9
print "{a.x} {b.x}" // 1 9A const binding to an object is not a read-only view of it. It fixes which object the name holds, the way a
let holds a class instance in Swift; the object changes through it like through every other holder. What cannot
change through a const is a value - which is why almost nothing is a shared type.
type Point {
var x: Int
}
const origin = Point 0
origin.x = 1
// error: `origin` is a `const`. Only a `var` binding can be changedRelated#
- Declaring a type - the value form
shared typeis the exception to. - Copy and equality -
Equals,Hashandcopy, generated for a value and not for an object. - Mutation and var paths - the
varpath rule a value follows and an object does not need.