Optionals and sentinels
Optionals and sentinels
Three states
Option<T> holds a value, None, or an error carrying a message. All three
are the same type.
[public] fn is_value() => bool
[public] fn is_none() => bool
[public] fn is_error() => bool
[public] fn unwrap() => TError("message") builds the error state. ? propagates a None or an error to
the caller; ? else { } handles both locally.
unwrap() on a non-value terminates the program after printing a failure
backtrace. It does not return a default and it is not recoverable, so guard with
is_value() or use ?.
What None means, per call
| Call | None means |
|---|---|
Array.first/last/pop |
the array is empty |
Array.find |
nothing matched |
Map.get, IndexMap.get, JsonObject.get |
the key is absent |
fs.read_file, fs.read_bytes |
the file could not be read |
FileHandle.read* |
end of file, an error, or the handle is closed |
File.open |
could not open |
io.read_line |
a read error, not distinguishable from end of input |
crypto.*_decrypt |
authentication failed |
crypto.from_hex/from_base64 |
the input was not valid |
sockets.Request.send/send_http |
transport error or an empty reply |
sockets.WsClient.recv |
the connection closed or errored |
threads.Channel.recv |
the channel is closed and drained |
threads.Channel.try_recv |
empty or closed, indistinguishable |
threads.Future.await |
the future was cancelled |
process.spawn/spawn_in/run |
the process could not start |
process.Process.read_line |
end of output |
process.Process.try_exit_code |
the child is still running |
random.choice |
the array is empty |
xml.Element.get_attribute |
the attribute is absent |
The sentinels
These do not use an optional, so nothing forces a check. They are the most common source of quiet bugs in Peko code.
| Call | Sentinel |
|---|---|
string.index_of |
-1 |
Array.index_of_where, search, linear_search, binary_search |
-1 |
process.Process.write, write_line |
a negative number |
sockets.send_request, send_request_tls, Request.send_raw |
a string starting with Error: |
string.to_number |
0 for non-numeric text |
random.next_int |
returns min when max <= min |
fs.list_dir |
an empty array for an unreadable directory |
pekoui env.get |
an empty string when unset |
Treat a -1 or a negative return as the failure case explicitly:
let written = child.write_line(payload)
if written < 0 {
return Error("could not write to the child process")
}