Regarding Mutual Exclusivity of THEN and ELSE

#1

The rule for voidification of conditionals at the moment is that branching constructs (IF, CASE, SWITCH, etc.) reserve the null result exclusively to mean a branch did not run. Hence if a branch evaluates to null, it is forced to VOID! instead.

>> type of (if true [null])
== void!

This has the pleasing result that you don't get suckered into running an ELSE branch in this case:

>> if true [some-incidentally-null-expression] else [print "Bad if this ran!"]
; void!

Note you don't get an error there, though you would if you tried to assign the result of that IF...ELSE to something. (I'm just rehashing the explanation of VOID! post here, go read that for more information.)

What about THEN and ELSE?

The THEN clause as introduced by Ren-C is a bit of an oddity of programming-language-THENs, because it exists even though you don't generally use it with an IF. You can, but you're just adding an extra clause:

 if condition [
     print "This prints if condition is true"
 ] then [
     print "And this will also print if condition is true"
 ]

It's a bit redundant with IF, though it may help you factor code. But THEN's main use is with more complex branching constructs like CASE or SWITCH, where you want to add code that runs if any of the branches ran.

However, one wonders if THEN itself is in the same category of "voidifying" branches or not. e.g.

if true [
    null
] then [
    null
] then [
    print "Should this print or not?"
]

We can look at the mirror question of ELSE's job regarding its output. Should it nullify it, to keep a nullsy chain all-nullsy...which would line up with voidifying a THEN chain to keep it all value-y?

if false [
    print "Doesn't print"
] else [
    true
] else [
    print "Should this print or not?"
]

But that absolutely should print. Because you want if condition [...] else [...] to act as much like either [...] [...] as possible. That means the ELSE branch should yield its result.

Yet should ELSE voidify its result?

if false [
    print "Doesn't print"
] else [
    null
] else [
    print "Should this print or not?"
]

That's a bit more subtle. The premise I decided to go with was that it should not print, e.g. ELSE passes through its result verbatim...without voidification of nulls. Because otherwise, the chain of ELSE...ELSE would never be useful. You'd never run the second ELSE!

So by a similar token, I decided THEN should also not voidify, to avoid chains of THEN...THEN always running together. It seemed strictly more powerful.

The consequence is that you have to be careful with some-branching-construct [...1...] then [...2...] else [...3...]. Because the 2 and 3 branches are not mutually exclusive. You have to read that as:

 (some-branching-construct [...1...] then [...2...]) else [...3...]

e.g.

 (black-box) else [...]

The ELSE is reacting to the overall result of that expression, which includes potentially reacting to the nullness of ...2...

While this defies the conventual notion of exclusivity of THEN and ELSE in most languages, it is strictly more powerful. The lack of a mandatory THEN on IF statements makes this seem like the better choice.

If we thought it worth the tradeoffs to use an arity-1 IF, this choice would absolutely be different. THEN would absolutely have to voidify its output. Because you'd want if (...) then [...] else [...] to have mutual exclusivity of the THEN and ELSE branches. But that's not how Rebol conditionals work.

So right now neither ELSE nor THEN voidify. I've tried it both ways, I can see both sides. But seems to me so long as we're covered for if condition [...] else [...] being mutually exclusive on its branches, I feel the THEN/ELSE chainers are going to be power users who are going to want all the flexibility they can get, which means not locking into a no-nulls-chain-state where you can only put one ELSE and you can't ever turn off the chain once you have one.