When an IF (or any other control construct, CASE or SWITCH etc) does not take a branch, you get VOID back.
>> if 10 = 20 [<unreachable>]
== \~\ ; antiform (void!)
Since IF is not a "vanishable" function, ALL sees the void as a heavy void, so this errors in Ren-C... as heavy void is neither truthy nor falsey:
ren-c>> all [if 10 = 20 [<a>] if 3 = 4 [<b>]]
** PANIC: Empty PACK! cannot decay to single value
This is different from historical Rebol, where a failing IF was falsey:
rebol2>> all [if 10 = 20 [<a>] if 3 = 4 [<b>]]
== none
Given that VOID (can be) unfriendly to logic testing, would it be better to make it return NULL?
Given that VOID (can be) unfriendly to logic testing, would it be better to make it return NULL?
You're free to redefine your own IF however you like... 
But I believe testing the result of an IF for truthiness is much less common than wanting it to vanish or opt-out of things:
>> compose [a b (if 1 = 2 ['q]) c d]
== [a b c d]
Were IF to return NULL, you'd get an error:
ren-c-null-if>> if 1 = 2 ['q]
== \~null~\ ; antiform
ren-c-null-if>> compose [a b (if 1 = 2 ['q]) c d]
** PANIC: ~null~ antiform cannot COMPOSE into lists
You'd have to somehow make this vanish using OPT to turn the null cases to VOID, or throw in empty branches:
ren-c-null-if>> compose [a b (opt if 1 = 2 ['q]) c d]
== [a b c d]
ren-c-null-if>> compose [a b (if 1 = 2 ['q] else []) c d]
== [a b c d]
ren-c-null-if>> compose [a b (either 1 = 2 ['q] []) c d]
== [a b c d]
ALL is Often a Good Replacement for "Nulling IF"
Very frequently you can just write, e.g.
>> all [10 = 20, <unreachable>]
== \~null~\ ; antiform
>> all [10 = 10, <reachable>]
== <reachable>
It's one of your many alternatives (along with either condition [...] [null] and all the other possibilities)... but in practice I think it tends to cover the desire pretty well.
1 Like