diff options
Diffstat (limited to 'api/pointers.md')
| -rw-r--r-- | api/pointers.md | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/api/pointers.md b/api/pointers.md new file mode 100644 index 00000000..67043084 --- /dev/null +++ b/api/pointers.md @@ -0,0 +1,104 @@ +# Pointers + +Pointers are numeric values that represent a location in memory where some type +of data lives. Pointers are created using either the `@` prefix operator to +**a**llocate heap memory or the `&` prefix operator to get the address of a +variable. Stack pointers (`&`) are more limited than heap pointers (`@`) and +cannot be stored inside an array, set, table, struct, enum, or channel. +However, stack pointers are useful for methods that mutate local variables and +don't need to save the pointer anywhere. + +Pointers are the way in Tomo that you can create mutable data. All +datastructures are by default, immutable, but using pointers, you can create +a region of memory where different immutable values can be held, which change +over time. + +```tomo +func no_mutation_possible(nums:[Int]): + nums[1] = 10 // Type error! + +func do_mutation(nums:@[Int]): + nums[1] = 10 // okay + +... + +my_nums := @[0, 1, 2] +do_mutation(my_nums) +``` + +In general, heap pointers can be used as stack pointers if necessary, since +the usage of stack pointers is restricted, but heap pointers don't have the +same restrictions, so it's good practice to define functions that don't need +to store pointers to use stack references. This lets you pass references to +local variables or pointers to heap data depending on your needs. + +```tomo +func swap_first_two(data:&[Int]): + data[1], data[2] = data[2], data[1] + +... + +heap_nums := @[10, 20, 30] +swap_first_two(heap_nums) + +local_nums := [10, 20, 30] +swap_first_two(&local_nums) +``` + +## Dereferencing + +Pointers can be dereferenced to access the value that's stored at the pointer's +memory location using the `[]` postfix operator (with no value inside). + +```tomo +nums := @[10, 20] +>> nums[] += [10, 20] +``` + +## Equality and Comparisons + +When comparing two pointers, the comparison operates on the _memory address_, +not the contents of the memory. This is "referential" equality, not +"structural" equality. The easy way to think about it is that two pointers are +equal to each other only if doing a mutation to one of them is the same as +doing a mutation to the other. + +```tomo +x := @[10, 20, 30] +y := @[10, 20, 30] +>> x == y += no + +z := x +>> x == z += yes +``` + +Pointers are ordered by memory address, which is somewhat arbitrary, but +consistent. + +## Null Safety + +Tomo pointers are, by default, guaranteed to be non-null. If you write a +function that takes either a `&T` or `@T`, the value that will be given +is always non-null. However, optional pointers can be used by adding a +question mark to the type: `&T?` or `@T?`. A null value can be created +using the syntax `!@T` or `!&T`. You can also append a question mark to +a pointer value so the type checker knows it's supposed to be optional: + +``` +optional := @[10, 20]? +optional := &foo? +``` + +The compiler will not allow you to dereference an optionally null pointer +without explicitly checking for null. To do so, use pattern matching like +this: + +``` +when optional is @ptr: + ok := ptr[] +else: + say("Oh, it was null") +``` |
