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:
|
||||
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