Guards
Guards are special constructs used to catch NIL
values in expressions. There are two guards, the ?
and the |
guard. The ?
guard has high lexicographic precedence and is used with variables or parenthesized expressions:
X = A? + 1. // Terminate the transaction if A is NIL, otherwise add 1 and assign to X.
Y = (B A)?. // Assign the result of (B A) to Y if it is not NIL or terminate with an error otherwise.
The |
guard is used to prevent delayed errors in expressions using reductions. For example, if F
is a collection of collections, you can subscript F
twice, but you need to use a guard if you are not sure that the corresponding element exists:
C = (1->("A"->"B"), 2->("C"->"D")).
X = C 3 | "A". // Terminates with an error if (C 3) does not exist
The
|
guard is technically not necessary because the error is produced anyway due toNIL
not being subscriptable. However, using the guard is a good practice because it preventsNIL
from leaking to downstream code causing hard-to-find bugs.
Guards as Casts
The ?
and |
guards are also casts that cast a nullable type into a non-nullable type, converting type X+
to a type X
after required runtime checks.
X is int+ = NIL.
// Y is int = X. // will cause a compile error because X is int+, which is not compatible with int
Y is int = X?. // valid but produces runtime error if X is NIL
Declarative Cast
Declarative cast uses the keyword as
and simply declares to the MUFL compiler that some value is compatible with a given type. For example, when assigning a string to a value list, it is sometimes important to declare that the value is compatible:
metadef theEnum:<$a,$b,$c>.
A is theEnum+ = NIL.
B is str = "a".
// invalid: A->B.
A -> B as(theEnum). // This is valid, but BE CAREFUL!
safe Cast
A safe
cast generates runtime code to check the validity of the value:
metadef theEnum:<$a,$b,$c>.
A is theEnum+ = NIL.
B is str = "WRONG".
A -> B safe(theEnum). // Does not cause a compile error, but fails at runtime because B is not compatible with A