Memory Model
It may be best to provide a comprehensive example of Ki memory management.
struct Pointers {
var person_value: Person("Charlie", 33)
var person_unique_pointer: *Person("Charlie", 33)
var person_arc_pointer: $Person("Charlie", 33)
var person_rc_pointer: ^Person("Charlie", 33)
var person_weak_pointer: ~Person
}
struct Person {
var name: string
var age: uint
}
fn bind() {
var person_value: Person("Charlie", 33)
var person_unique_pointer: *Person("Charlie", 33)
var person_arc_pointer: $Person("Charlie", 33)
var person_rc_pointer: ^Person("Charlie", 33)
var person_weak_arc_pointer: ~person_arc_pointer
var person_weak_rc_pointer: ~person_rc_pointer
var person_value_ref: &person_value
var person_unique_pointer_ref: &person_unique_pointer
var person_arc_pointer_ref: &person_arc_pointer
var person_rc_pointer_ref: &person_rc_pointer
var person_value_mutable_ref: &person_value!
var person_unique_pointer_mutable_ref: &person_unique_pointer!
var person_arc_pointer_mutable_ref: &person_arc_pointer!
var person_rc_pointer_mutable_ref: &person_rc_pointer!
}
fn weak_bind() {
var person_arc_pointer: $Person("Charlie", 33)
var person_rc_pointer: ^Person("Charlie", 33)
var person_weak_arc_pointer: ~person_arc_pointer
var person_weak_rc_pointer: ~person_rc_pointer
}
fn ref_bind() {
var person_value: Person("Charlie", 33)
var person_unique_pointer: *Person("Charlie", 33)
var person_arc_pointer: $Person("Charlie", 33)
var person_rc_pointer: ^Person("Charlie", 33)
var person_value_ref: &person_value
var person_unique_pointer_ref: &person_unique_pointer
var person_arc_pointer_ref: &person_arc_pointer
var person_rc_pointer_ref: &person_rc_pointer
}
fn mutable_ref_bind() {
var person_value: Person("Charlie", 33)
var person_unique_pointer: *Person("Charlie", 33)
var person_arc_pointer: $Person("Charlie", 33)
var person_rc_pointer: ^Person("Charlie", 33)
var person_value_mutable_ref: &person_value!
var person_unique_pointer_mutable_ref: &person_unique_pointer!
var person_arc_pointer_mutable_ref: &person_arc_pointer!
var person_rc_pointer_mutable_ref: &person_rc_pointer!
}
fn print_person_value(p: Person) {
echo("{{p.name}} is {{p.age}} years old")
}
fn print_person_pointer(p: *Person) {
echo("{{p.name}} is {{p.age}} years old")
}
fn print_person_weak_pointer(weakp: ~Person) {
with (p: weakp) {
echo("{{p.name}} is {{p.age}} years old")
}
}
fn print_person_reference(p: &Person) {
echo("{{p.name}} is {{p.age}} years old")
}
fn print_person_mutable_reference(p: &Person!) {
p.age++
echo("{{p.name}} is {{p.age - 1}} years old")
p.age--
}
fn get_person_value(): (Person) {
return(Person("Charlie", 33))
}
fn get_person_unique_pointer(): (*Person) {
return(*Person("Charlie", 33))
}
fn get_person_arc_pointer(): (*Person) {
return($Person("Charlie", 33))
}
fn get_person_rc_pointer(): (*Person) {
return(^Person("Charlie", 33))
}
# Not great, because getting a weak pointer from a shared pointer is fine, but
# getting a weak pointer from a unique pointer is not fine, and `*Person`
# obscures this issue because it refers to both unique and shared pointers.
# But, all in all, not the worst.
fn get_person_weak_pointer(p: *Person): (~Person) {
return(~p)
}
fn main() {
var person_value: get_person_value()
var person_unique_pointer: get_person_unique_pointer()
var person_arc_pointer: get_person_arc_pointer()
var person_rc_pointer: get_person_rc_pointer()
# Creates a copy of person_value; pretty inefficient
print_person_value(person_value)
# This is much more efficient
print_person_reference(&person_value)
# We can also pass mutable references in case we want to change the passed
# value
print_person_mutable_reference(&person_value!)
# Because print_person_reference only takes a reference,
# person_unique_pointer can be after this call.
print_person_reference(&person_unique_pointer)
# Same deal with mutability here
print_person_mutable_reference(&person_unique_pointer!)
# However, after this call person_unique_pointer cannot be used in this
# scope or any lower scopes. It moves into print_person_pointer's scope
# and is deallocated when that scope closes.
print_person_pointer(person_unique_pointer)
# These pointers, on the other hand, count their copies and will not be
# deallocated when print_person_pointer's scope closes.
print_person_pointer(person_arc_pointer)
print_person_pointer(person_rc_pointer)
# This will only print the person if person_arc_pointer is still valid,
# which it is.
print_person_weak_pointer(~person_arc_pointer)
}