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 toNILnot being subscriptable. However, using the guard is a good practice because it preventsNILfrom 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