More docs
This commit is contained in:
parent
6f3b2c073a
commit
2846ead8b8
88
api/enums.md
Normal file
88
api/enums.md
Normal file
@ -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()`).
|
@ -102,3 +102,24 @@ when optional is @ptr:
|
|||||||
else:
|
else:
|
||||||
say("Oh, it was null")
|
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
|
||||||
|
```
|
||||||
|
39
api/structs.md
Normal file
39
api/structs.md
Normal file
@ -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.
|
Loading…
Reference in New Issue
Block a user