-
-
Notifications
You must be signed in to change notification settings - Fork 55
Description
This feature was designed to help with #635.
A lazy invariant is a value that the functions returns immediately when the argument has the value. This makes it unnecessary to evaluate the rest of the arguments. When a lazy invariant is specified, the runtime checks the argument value before evaluating the rest of the arguments and calling the function. If the value matches the lazy variant, the runtime returns the value immediately.
Example (pseudocode):
use std as std
fn and(a: bool => false, b: bool) -> bool {return std::and_also(a, b)}
This makes the and
function behave exactly like the &&
operator.
One can use lazy invariants on other types than bool
and on multiple arguments:
Example:
use std as std
fn mul(a: f64 => 0, b: f64 => 0) -> f64 {return std::mul(a, b)}
When either a
or b
is 0
, the runtime returns 0
immediately instead of calling the function and evaluating the function body. However, the argument a
is evaluated before b
.
Lazy invariants improve performance when evaluating arguments or function body is expensive.
// The intersection of two sets returns `[]` immediately if either set is empty.
fn intersect(a: [] => [], b: [] => []) -> [] { ... }
A list of lazy invariants can be used to handle operations on dynamical types, e.g:
fn concat(a: any => [] | "", b: any => [] | "") -> any { ... }
Normal arguments might therefore be considered lazy invariants with length zero.
The syntax ok(_)
, err(_)
, some(_)
can be used to unwrap automatically without evaluating the rest of the arguments. The syntax _
is used to return the argument.
For example, the unwrap_or
function is be declared such that the default value is lazy evaluated:
fn unwrap_or(var: any => ok(_) | some(_), def: any) -> any { ... }