aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/arrays.md8
-rw-r--r--docs/booleans.md6
-rw-r--r--docs/integers.md10
-rw-r--r--docs/iterators.md8
-rw-r--r--docs/moments.md4
-rw-r--r--docs/nums.md3
-rw-r--r--docs/optionals.md85
-rw-r--r--docs/paths.md8
-rw-r--r--docs/pointers.md2
-rw-r--r--docs/reductions.md4
-rw-r--r--docs/tables.md8
-rw-r--r--docs/text.md12
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]?
```
---