diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/arrays.md | 8 | ||||
| -rw-r--r-- | docs/booleans.md | 6 | ||||
| -rw-r--r-- | docs/integers.md | 10 | ||||
| -rw-r--r-- | docs/iterators.md | 8 | ||||
| -rw-r--r-- | docs/moments.md | 4 | ||||
| -rw-r--r-- | docs/nums.md | 3 | ||||
| -rw-r--r-- | docs/optionals.md | 85 | ||||
| -rw-r--r-- | docs/paths.md | 8 | ||||
| -rw-r--r-- | docs/pointers.md | 2 | ||||
| -rw-r--r-- | docs/reductions.md | 4 | ||||
| -rw-r--r-- | docs/tables.md | 8 | ||||
| -rw-r--r-- | docs/text.md | 12 |
12 files changed, 121 insertions, 37 deletions
diff --git a/docs/arrays.md b/docs/arrays.md index 144bcd77..b69ae259 100644 --- a/docs/arrays.md +++ b/docs/arrays.md @@ -363,10 +363,10 @@ The index of the first occurrence or `!Int` if not found. **Example:** ```tomo >> [10, 20, 30, 40, 50]:find(20) -= 2? += 2 : Int? >> [10, 20, 30, 40, 50]:find(9999) -= !Int += NULL : Int? ``` --- @@ -394,9 +394,9 @@ item matches. **Example:** ```tomo >> [4, 5, 6]:find(func(i:&Int): i:is_prime()) -= 5? += 5 : Int? >> [4, 6, 8]:find(func(i:&Int): i:is_prime()) -= !Int += NULL : Int? ``` --- diff --git a/docs/booleans.md b/docs/booleans.md index 80de6fa6..3537e3ee 100644 --- a/docs/booleans.md +++ b/docs/booleans.md @@ -29,9 +29,9 @@ func parse(text: Text -> Bool?) **Example:** ```tomo >> Bool.parse("yes") -= yes? += yes : Bool? >> Bool.parse("no") -= no? += no : Bool? >> Bool.parse("???") -= !Bool += NULL : Bool? ``` diff --git a/docs/integers.md b/docs/integers.md index f5e6838b..d995d139 100644 --- a/docs/integers.md +++ b/docs/integers.md @@ -171,22 +171,22 @@ func parse(text: Text -> Int?) **Returns:** The integer represented by the text. If the given text contains a value outside of the representable range or if the entire text can't be parsed as an integer, -a null value will be returned. +`NULL` will be returned. **Example:** ```tomo >> Int.parse("123") -= 123? += 123 : Int? >> Int.parse("0xFF") -= 255? += 255 : Int? # Can't parse: >> Int.parse("asdf") -= !Int += NULL : Int? # Outside valid range: >> Int8.parse("9999999") -= !Int += NULL : Int8? ``` --- diff --git a/docs/iterators.md b/docs/iterators.md index 63a44fcf..ee777cfe 100644 --- a/docs/iterators.md +++ b/docs/iterators.md @@ -16,13 +16,13 @@ successively gets one line from a file at a time until the file is exhausted: >> iter := (./test.txt):each_line() >> iter() -= "line one"? += "line one" : Text? >> iter() -= "line two"? += "line two" : Text? >> iter() -= "line three"? += "line three" : Text? >> iter() -= !Text += NULL : Text? for line in (./test.txt):each_line(): pass diff --git a/docs/moments.md b/docs/moments.md index 58643eb6..6e2ac234 100644 --- a/docs/moments.md +++ b/docs/moments.md @@ -523,7 +523,7 @@ Returns a `Moment` object representing the current date and time. **Description:** Return a new `Moment` object parsed from the given string in the given format, -or a null value if the value could not be successfully parsed. +or `NULL` if the value could not be successfully parsed. **Signature:** ```tomo @@ -539,7 +539,7 @@ func parse(text: Text, format: Text = "%Y-%m-%dT%H:%M:%S%z" -> Moment?) **Returns:** If the text was successfully parsed according to the given format, return a -`Moment` representing that information. Otherwise, return a null value. +`Moment` representing that information. Otherwise, return `NULL`. **Example:** ```tomo diff --git a/docs/nums.md b/docs/nums.md index c7171f37..0b55f71e 100644 --- a/docs/nums.md +++ b/docs/nums.md @@ -583,7 +583,8 @@ func parse(text: Text -> Num?) - `text`: The text containing the number. **Returns:** -The number represented by the text or a null value if the entire text can't be parsed as a number. +The number represented by the text or `NULL` if the entire text can't be parsed +as a number. **Example:** ```tomo diff --git a/docs/optionals.md b/docs/optionals.md index 2bc747f9..bb2aecfd 100644 --- a/docs/optionals.md +++ b/docs/optionals.md @@ -27,7 +27,75 @@ func maybe_takes_int(x:Int?): This establishes a common language for talking about optional values without having to use a more generalized form of `enum` which may have different naming -conventions and which would generate a lot of unnecessary code. +conventions and which would generate a lot of unnecessary code. + +## Syntax + +Optional types are written using a `?` after the type name. So, an optional +integer would be written as `Int?` and an optional array of texts would be +written as `[Text]?`. + +Null values can be written explicitly using the `!` prefix operator and the +type of null value. For example, if you wanted to declare a variable that could +be either an integer value or a null value and initialize it as a null value, +you would write it as: + +```tomo +x := !Int +``` + +Similarly, if you wanted to declare a variable that could be an array of texts +or null and initialize it as null, you would write: + +```tomo +x := ![Text] +``` + +If you want to declare a variable and initialize it with a non-null value, but +keep open the possibility of assigning a null value later, you can use the +postfix `?` operator to indicate that a value is optional: + +```tomo +x := 5? +# Later on, assign null: +x = !Int +``` + +## Type Inference + +For convenience, null values can also be written as `NULL` for any type in +situations where the compiler knows what type of optional value is expected: + +- When assigning to a variable that has already been declared as optional. +- When returning from a function with an explicit optional return type. +- When passing an argument to a function with an optional argument type. + +Here are some examples: + +```tomo +x := 5? +x = NULL + +func doop(arg:Int?)->Text?: + return NULL + +doop(NULL) +``` + +Non-null values can also be automatically promoted to optional values without +the need for an explicit `?` operator in the cases listed above: + +```tomo +x := !Int +x = 5 + +func doop(arg:Int?)->Text?: + return "okay" + +doop(123) +``` + +## Null Checking In addition to using conditionals to check for null values, you can also use `or` to get a non-null value by either providing an alternative non-null value @@ -55,3 +123,18 @@ for line in lines: # The `or skip` above means that if we're here, `matches` is non-null: do_stuff(matches) ``` + +## Implementation Notes + +The implementation of optional types is highly efficient and has no memory +overhead for pointers, collection types (arrays, sets, tables, channels), +booleans, texts, enums, nums, or integers (`Int` type only). This is done by +using carefully chosen values, such as `0` for pointers, `2` for booleans, or a +negative length for arrays. However, for fixed-size integers (`Int64`, `Int32`, +`Int16`, and `Int8`), bytes, and structs, an additional byte is required for +out-of-band information about whether the value is null or not. + +Floating point numbers (`Num` and `Num32`) use `NaN` to represent null, so +optional nums should be careful to avoid using `NaN` as a non-null value. This +option was chosen to minimize the memory overhead of optional nums and because +`NaN` literally means "not a number". diff --git a/docs/paths.md b/docs/paths.md index 86ec2f26..b2dfe384 100644 --- a/docs/paths.md +++ b/docs/paths.md @@ -492,10 +492,10 @@ raised. **Example:** ```tomo >> (./hello.txt):read() -= "Hello"? += "Hello" : Text? >> (./nosuchfile.xxx):read() -= !Text += NULL : Text? ``` --- @@ -521,10 +521,10 @@ returned. **Example:** ```tomo >> (./hello.txt):read() -= [72[B], 101[B], 108[B], 108[B], 111[B]]? += [72[B], 101[B], 108[B], 108[B], 111[B]] : [Byte]? >> (./nosuchfile.xxx):read() -= ![Byte] += NULL : [Byte]? ``` --- diff --git a/docs/pointers.md b/docs/pointers.md index 174c4296..f1bd1b5a 100644 --- a/docs/pointers.md +++ b/docs/pointers.md @@ -113,7 +113,7 @@ inside of any datastructures as elements or members. ```tomo nums := @[10, 20, 30] >> nums:first(func(x:&Int): x / 2 == 10) -= 2? += 2 : Int? ``` Normal `@` pointers can be promoted to immutable view pointers automatically, diff --git a/docs/reductions.md b/docs/reductions.md index b4e78624..2ed6879f 100644 --- a/docs/reductions.md +++ b/docs/reductions.md @@ -8,7 +8,7 @@ infix operator followed by a colon, followed by a collection: nums := [10, 20, 30] sum := (+: nums) >> sum -= 60? += 60 : Int? ``` Reductions return an optional value which will be a null value if the thing @@ -22,7 +22,7 @@ nums := [:Int] sum := (+: nums) >> sum -= !Int += NULL : Int? >> sum or 0 = 0 diff --git a/docs/tables.md b/docs/tables.md index 1de58118..6a6c7004 100644 --- a/docs/tables.md +++ b/docs/tables.md @@ -48,9 +48,9 @@ was found or error if it wasn't: ```tomo >> t := {"x":1, "y":2} >> t:get("x") -= 1? += 1 : Int? >> t:get("????") -= !Int += NULL : Int? >> t:get("x")! = 1 ``` @@ -187,10 +187,10 @@ The value associated with the key or null if the key is not found. ```tomo >> t := {"A":1, "B":2} >> t:get("A") -= 1? : Int? += 1 : Int? >> t:get("????") -= !Int : Int? += NULL : Int? >> t:get("A")! = 1 : Int diff --git a/docs/text.md b/docs/text.md index 7557f05c..d433e902 100644 --- a/docs/text.md +++ b/docs/text.md @@ -693,13 +693,13 @@ containing information about the match. **Example:** ```tomo >> " #one #two #three ":find($/#{id}/, start=-999) -= !Match += NULL : Match? >> " #one #two #three ":find($/#{id}/, start=999) -= !Match += NULL : Match? >> " #one #two #three ":find($/#{id}/) -= Match(text="#one", index=2, captures=["one"])? += Match(text="#one", index=2, captures=["one"]) : Match? >> " #one #two #three ":find("{id}", start=6) -= Match(text="#two", index=9, captures=["two"])? += Match(text="#two", index=9, captures=["two"]) : Match? ``` --- @@ -885,10 +885,10 @@ or a null value otherwise. **Example:** ```tomo >> "hello world":matches($/{id}/) -= ![Text] += NULL : [Text]? >> "hello world":matches($/{id} {id}/) -= ["hello", "world"]? += ["hello", "world"] : [Text]? ``` --- |
