diff --git a/api/enums.md b/api/enums.md new file mode 100644 index 0000000..4123fbc --- /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 6704308..6fc2901 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 0000000..4ab78fe --- /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.