Closed
Description
Right now, we have a partial implementation of three-valued logic because the left-hand side of short-circuiting Boolean operators is checked for Bool typing at run-time, but the right-hand side is not checked for Bool typing if the operation short-circuits, since this would requiring evaluating the right-hand expression. This produces particularly odd results when you introduce Nullable{Bool}()
into the mix, because you end up with things like:
julia> true || Nullable{Bool}()
true
julia> Nullable{Bool}() || true
ERROR: type: non-boolean (Nullable{Bool}) used in boolean context
julia> false && Nullable{Bool}()
false
julia> Nullable{Bool}() && false
ERROR: type: non-boolean (Nullable{Bool}) used in boolean context
I don't see any unambiguously correct solution to this given Julia's dynamic typing and the design objectives of Boolean operators in Base Julia, but there are some possible approaches:
- Make
||
and&&
into a special evaluation rule that can be extended via dispatch. This has the undesirable consequence of allowing people to add truthiness to the language via possible extensions to Boolean operations. - Add special handling for
Nullable
arguments to||
and&&
so that we can implement three-valued logic in full. - Verbally prohibit the implementation of three-valued logic, but note that the short-circuiting nature of
||
and&&
combined with run-time typing means that some cases will not raise errors despite being incorrect uses of||
and&&
by convention.
Obviously, this all interacts with the Julia idiom of doing control-flow via Boolean operations.