Recently I have been pondering how to propagate contract failures or not. I want this to be controlled - a contract failure shouldn't propagate accidentally.
So I have devised a system as such, firstly to "catch" a contract failure, use .?
with ||
:
x.?foo(1) || not accepted
Methods can define contracts as part of the signature, this is translated into a precondition of the method, notated using &&&
:
{ foo(n) = (n != 1) &&& (n) }
To propagate a precondition failure, as one will often want to do in a higher-order function, you can use a precondition:
{ (x # y) = y.?foo &&& y.foo
The expression is repeat here, in a way, but the system should be able to optimize this to be free.
This leads to a definition of the "variant" syntax feature where #foo = { (x # y) = y.?foo &&& y.foo
and thus (#foo #? {}) || fallback) == fallback
, now we can provide the "default" case for a visitor.