aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/enums.md88
-rw-r--r--api/pointers.md21
-rw-r--r--api/structs.md39
3 files changed, 148 insertions, 0 deletions
diff --git a/api/enums.md b/api/enums.md
new file mode 100644
index 00000000..4123fbc4
--- /dev/null
+++ b/api/enums.md
@@ -0,0 +1,88 @@
+# Enums
+
+Tomo supports tagged enumerations, also known as "sum types." Users
+can define their own using the `enum` keyword:
+
+```tomo
+enum VariousThings(AnInteger(i:Int), TwoWords(word1, word2:Text), Nothing)
+
+...
+
+a := VariousThings.AnInteger(5)
+b := VariousThings.TwoWords("one", "two")
+c := VariousThings.Nothing
+```
+
+## Pattern Matching
+
+The values inside an enum can be accessed with pattern matching:
+
+```tomo
+when x is AnInteger(i):
+ say("It was $i")
+is TwoWords(x, y):
+ say("It was $x and $y")
+is Nothing:
+ say("It was nothing")
+```
+
+Pattern matching blocks are always checked for exhaustiveness, but you can add
+an `else` block to handle all unmatched patterns.
+
+## Tag Checking
+
+Tags can also be quickly checked using the `.TagName` field:
+
+```tomo
+>> a.AnInteger
+= yes
+>> a.TwoWords
+= no
+```
+
+## Reducing Boilerplate
+
+There are three main areas where we can easily reduce the amount of boilerplate
+around enums. We don't need to type `VariousThings.` in front of enum values
+when we already know what type of enum we're dealing with. This means that we
+don't need the name of the type for pattern matching (because we can infer the
+type of the expression being matched). We also don't need the name of the type
+when calling a function with an enum argument, nor when returning an enum value
+from a function with an explicit return type:
+
+```tomo
+enum ArgumentType(AnInt(x:Int), SomeText(text:Text))
+enum ReturnType(Nothing, AnInt(x:Int))
+
+func increment(arg:ArgumentType)->ReturnType:
+ when arg is AnInt(x):
+ return AnInt(x + 1)
+ is SomeText:
+ return Nothing
+
+...
+
+>> increment(AnInt(5))
+= ReturnType.AnInt(6)
+>> increment(SomeText("HI"))
+= ReturnType.Nothiing
+```
+
+This lets us have overlapping tag names for different types, but smartly infer
+which enum's value is being created when we know what we're expecting to get.
+This also works for variable assignment to a variable whose type is already
+known.
+
+## Namespacing
+
+Enums can also define their own methods and variables inside their namespace:
+
+```tomo
+enum VariousThings(AnInteger(i:Int), TwoWords(word1, word2:Text), Nothing):
+ meaningful_thing := AnInteger(42)
+ func doop(v:VariousThings):
+ say("$v")
+```
+
+Functions defined in an enum's namespace can be invoked as methods with `:` if
+the first argument is the enum's type or a pointer to one (`vt:doop()`).
diff --git a/api/pointers.md b/api/pointers.md
index 67043084..6fc29013 100644
--- a/api/pointers.md
+++ b/api/pointers.md
@@ -102,3 +102,24 @@ when optional is @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
+```
diff --git a/api/structs.md b/api/structs.md
new file mode 100644
index 00000000..4ab78fed
--- /dev/null
+++ b/api/structs.md
@@ -0,0 +1,39 @@
+# Structs
+
+In Tomo, you can define your own structs, which hold members with arbitrary
+types that can be accessed by fields:
+
+```tomo
+struct Foo(name:Text, age:Int)
+...
+>> my_foo := Foo("Bob", age=10)
+= Foo(name="Bob", age=10)
+>> my_foo.name
+= "Bob"
+```
+
+Structs are value types and comparisons on them operate on the member values
+one after the other.
+
+## Namespaces
+
+Structs can define their own methods that can be called with a `:` or different
+values that are stored on the type itself.
+
+```tomo
+struct Foo(name:Text, age:Int):
+ oldest := Foo("Methuselah", 969)
+
+ func greet(f:Foo):
+ say("Hi my name is $f.name and I am $f.age years old!")
+
+ func get_older(f:&Foo):
+ f.age += 1
+...
+my_foo := Foo("Alice", 28)
+my_foo:greet()
+my_foo:get_older()
+```
+
+Method calls work when the first argument is the struct type or a pointer to
+the struct type.