code / tomo

Lines41.3K C23.7K Markdown9.7K YAML5.0K Tomo2.3K
7 others 763
Python231 Shell230 make212 INI47 Text21 SVG16 Lua6
(114 lines)

Pointers

Pointers are numeric values that represent a location in memory where some type of data lives. Pointers are created using the @ prefix operator to allocate heap memory.

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.

func no_mutation_possible(nums:[Int])
    nums[1] = 10 // This performs a copy-on-write and creates a new list
    // The new list is only accessible as a local variable here
...
my_nums := [0, 1, 2]
no_mutation_possible(my_nums)
assert 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)
assert my_nums == @[10, 1, 2]

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

nums := @[10, 20]
assert 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.

x := @[10, 20, 30]
y := @[10, 20, 30]
assert x != y

z := x
assert x == z

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 a @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?. A null value can be created using the syntax !@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]?

The compiler will not allow you to dereference an optionally null pointer without explicitly checking for null. To do so, use a conditional check like this, and everywhere inside the truthy block will allow you to use the pointer as a non-null pointer:

if optional
    ok := optional[]
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 list accesses like ptr[i] and method calls like ptr.reversed().

Read-Only Views

In a small number of API methods (list.first(), list.binary_search(), list.sort(), list.sorted(), and list.heapify()), the methods allow you to provide custom comparison functions. However, for safety, we don't actually want the comparison methods to be able mutate the values inside of immutable list values. For implementation reasons, we can't pass the values themselves to the comparison functions, but need to pass pointers to the list members. So, to work around this, Tomo allows you to define functions that take immutable view pointers as arguments. These behave similarly to @ pointers, but their type signature uses & instead of @ and read-only view pointers cannot be used to mutate the contents that they point to and cannot be stored inside of any datastructures as elements or members.

nums := @[10, 20, 30]
assert nums.first(func(x:&Int): x / 2 == 10) == 2

Normal @ pointers can be promoted to immutable view pointers automatically, but not vice versa.

1 # Pointers
3 Pointers are numeric values that represent a location in memory where some type
4 of data lives. Pointers are created using the `@` prefix operator to
5 **a**llocate heap memory.
7 Pointers are the way in Tomo that you can create mutable data. All
8 datastructures are by default, immutable, but using pointers, you can create
9 a region of memory where different immutable values can be held, which change
10 over time. Essentially, you can think about mutation as the act of creating
11 a new, different value and assigning it to a pointer's memory location to
12 replace the value that previously resided there.
14 ```tomo
15 func no_mutation_possible(nums:[Int])
16 nums[1] = 10 // This performs a copy-on-write and creates a new list
17 // The new list is only accessible as a local variable here
18 ...
19 my_nums := [0, 1, 2]
20 no_mutation_possible(my_nums)
21 assert my_nums == [0, 1, 2]
23 func do_mutation(nums:@[Int])
24 nums[1] = 10 // The mutates the value at the given pointer's location
25 ...
26 my_nums := @[0, 1, 2]
27 do_mutation(my_nums)
28 assert my_nums == @[10, 1, 2]
29 ```
31 ## Dereferencing
33 Pointers can be dereferenced to access the value that's stored at the pointer's
34 memory location using the `[]` postfix operator (with no value inside).
36 ```tomo
37 nums := @[10, 20]
38 assert nums[] == [10, 20]
39 ```
41 ## Equality and Comparisons
43 When comparing two pointers, the comparison operates on the _memory address_,
44 not the contents of the memory. This is "referential" equality, not
45 "structural" equality. The easy way to think about it is that two pointers are
46 equal to each other only if doing a mutation to one of them is the same as
47 doing a mutation to the other.
49 ```tomo
50 x := @[10, 20, 30]
51 y := @[10, 20, 30]
52 assert x != y
54 z := x
55 assert x == z
56 ```
58 Pointers are ordered by memory address, which is somewhat arbitrary, but
59 consistent.
61 ## Null Safety
63 Tomo pointers are, by default, guaranteed to be non-null. If you write a
64 function that takes a `@T`, the value that will be given is always non-null.
65 However, optional pointers can be used by adding a question mark to the type:
66 `@T?`. A null value can be created using the syntax `!@T`. You can also append
67 a question mark to a pointer value so the type checker knows it's supposed to
68 be optional:
70 ```
71 optional := @[10, 20]?
72 ```
74 The compiler will not allow you to dereference an optionally null pointer
75 without explicitly checking for null. To do so, use a conditional check like
76 this, and everywhere inside the truthy block will allow you to use the pointer
77 as a non-null pointer:
79 ```
80 if optional
81 ok := optional[]
82 else
83 say("Oh, it was null")
84 ```
86 ## Using Pointers
88 For convenience, most operations that work on values can work with pointers to
89 values implicitly. For example, if you have a struct type with a `.foo` field,
90 you can use `ptr.foo` on a pointer to that struct type as well, without needing
91 to use `ptr[].foo`. The same is true for list accesses like `ptr[i]` and method
92 calls like `ptr.reversed()`.
94 # Read-Only Views
96 In a small number of API methods (`list.first()`, `list.binary_search()`,
97 `list.sort()`, `list.sorted()`, and `list.heapify()`), the methods allow you
98 to provide custom comparison functions. However, for safety, we don't actually
99 want the comparison methods to be able mutate the values inside of immutable
100 list values. For implementation reasons, we can't pass the values themselves
101 to the comparison functions, but need to pass pointers to the list members.
102 So, to work around this, Tomo allows you to define functions that take
103 immutable view pointers as arguments. These behave similarly to `@` pointers,
104 but their type signature uses `&` instead of `@` and read-only view pointers
105 cannot be used to mutate the contents that they point to and cannot be stored
106 inside of any datastructures as elements or members.
108 ```tomo
109 nums := @[10, 20, 30]
110 assert nums.first(func(x:&Int): x / 2 == 10) == 2
111 ```
113 Normal `@` pointers can be promoted to immutable view pointers automatically,
114 but not vice versa.