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)
}