diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2024-08-19 00:23:02 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2024-08-19 00:23:02 -0400 |
| commit | 67e8f2dea0d4eec20a839d47f1fa6302a4a5f733 (patch) | |
| tree | 3f9d28687b6ac824b5676c963ef9964ac4857c4a /api/pointers.md | |
| parent | 8363d53bd27c621cb342fea15736a3b11231f2a4 (diff) | |
Move docs into one folder
Diffstat (limited to 'api/pointers.md')
| -rw-r--r-- | api/pointers.md | 133 |
1 files changed, 0 insertions, 133 deletions
diff --git a/api/pointers.md b/api/pointers.md deleted file mode 100644 index ee7a5d8f..00000000 --- a/api/pointers.md +++ /dev/null @@ -1,133 +0,0 @@ -# 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. Essentially, you can think about mutation as the act of creating -a new, different value and assigning it to a pointer's memory location to -replace the value that previously resided there. - -```tomo -func no_mutation_possible(nums:[Int]): - nums[1] = 10 // This performs a copy-on-write and creates a new array - // The new array is only accessible as a local variable here -... -my_nums := [0, 1, 2] -no_mutation_possible(my_nums) ->> my_nums -= [0, 1, 2] - -func do_mutation(nums:@[Int]): - nums[1] = 10 // The mutates the value at the given pointer's location -... -my_nums := @[0, 1, 2] -do_mutation(my_nums) ->> my_nums -= @[10, 1, 2] -``` - -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") -``` - -## Using Pointers - -For convenience, most operations that work on values can work with pointers to -values implicitly. For example, if you have a struct type with a `.foo` field, -you can use `ptr.foo` on a pointer to that struct type as well, without needing -to use `ptr[].foo`. The same is true for array accesses like `ptr[i]` and method -calls like `ptr:reversed()`. - -As a matter of convenience, local variables can also be automatically promoted -to stack references when invoking methods that require a stack reference as the -first argument. For example: - -```tomo -func swap_first_two(arr:&[Int]): - arr[1], arr[2] = arr[2], arr[1] -... -my_arr := [10, 20, 30] // not a pointer -swap_first_two(my_arr) // ok, automatically converted to &my_arr -my_arr:shuffle() // ok, automatically converted to &my_arr -``` |
