Pointers
September 30, 2024 ยท View on GitHub
There are several pointer types:
X*- raw pointersX&- referencesowned[X]- single ownerowned![X]- single owned, not nullshared[X]- shared ownershipshared![X]- shared ownership, not nullxfer[X]- ownership transfer
New
๐ฅ Objects created with the new operator have ownership:
var a = new X() # type: owned![X]
var b = new shared X() # type: shared![X]
Pointers as containers
Pointers that can be null (X*, owned[X], shared[X]) need additional unwrapping when using the "contained" value (i.e. the object pointed to by the pointer) (see error handling):
var pointer: shared[X]
for x in pointer
x.do_something()
else
print("null pointer...")
This ensures, that no null pointers are dereferenced.
The extracted value is of reference type X&.
References
References (as well as not-null-pointers owned![X], shared![X]) will be dereferenced automativally:
var pointer = new X() # type: owned![X]
pointer.do_something()
var x: X
var r = &x # type: X&
r.do_something()
References should be seen as a temporary view, always pointing to a value.
Single ownership
Only owned and shared pointers take ownership.
For owned that means, destroying or altering the pointer will delete the pointed to object:
func main()
let x = new X()
# by default, x has type owned![X]
...
x = new X() # deletes the old object
...
# here `x` goes out of scope, also deleting the new object
When there is an owned[X], no other pointer with ownership can exist simultaneously. Ownership has to be transferred:
var a: owned[X] = new X()
var b: owned[X]
b = give(a)
# now, a is null
Here give(a) clears the pointer a and returns a transfer pointer of type xfer[X]. b then takes the ownership.
Likewise, ownership has to be transferred in and out of functions:
func ownership_taker(x: xfer[X])
var p: owned[X] = x
func ownership_giver() -> xfer[X]
var p = new X[]
return give(p)
ownership_taker(ownership_giver())
๐ฅ Btw. new X() returns a type xfer[X]. But since no variables of type xfer[X] are allowed, new variables default to owned![X]:
var p = new X()
# -> owned![X]
Shared ownership
Similar to owned[X], shared[X] also owns an object. Although multiple shared[X] pointers can point to the same object. The object is deleted, when no shared pointer points to it anymore:
var a: shared[X] = new X()
var b = a
# now, both a and b point to the same object
a = nil
# object still alive
b = nil
# object is deleted
๐ฅ owned and shared should not be mixed for the same object! Future plans for the language include more safe guards.
Recommendations
When storing data, use owned(!)[X] and shared(!)[X]:
struct MyData
a: owned[X]
b: shared[X][]
Functions should indicate ownership. If ownership is fully taken/given, indicate with xfer[X]:
func taker(p: xfer[X])
some_owner = p
# this is now the only owner
func giver() -> xfer[X]
return new X()
# caller is the only owner
Shared ownership via shared[X]:
func taker(p: shared[X])
some_shared = p
# caller might sill own, too
func giver() -> shared[X]
return x
# caller might not be the only owner