ELSE and OR can be used for similar-looking purposes, but they have an important difference.
ELSE runs its right hand side when there's a void on its left:
>> () else [print "left hand side is void, branch runs" 10]
left hand side is void, branch runs
== 10
>> false else [print "left hand side is not void, branch skipped" 10]
;-- no result
Whereas OR doesn't tolerate voids on its left, and reacts to conditionally false things on its left:
>> false or [print "left hand side is 'falsey', branch runs" 10]
left hand side is 'falsey', branch runs
== 10
>> 20 or [print "left hand side is 'truthy', left hand returned" 10]
== 20
>> false or [print "both false means blank! result" false]
== _
>> () or [print "left hand can't be void"]
** Error: left hand side of OR can't be void
Here we see the behavior of OR when a BLOCK! is used as its right hand side. It is similar to an ANY, because it will give back the first value it calculates or a BLANK!. However, if you use a GROUP! for the right hand side, the result will be forced to a LOGIC!:
>> 1 or (2)
== #[true]
>> false or (_)
== #[false]
>> 1 or [2]
== 1
>> false or [2]
== 2
>> false or [false]
== _
(An additional constraint is that if you use a GROUP! on the right hand side, then should the right hand side be evaluated--e.g. it wasn't a short circuit--it cannot be void. A BLOCK! on the right tolerate voids, treating them like blanks.)
In any case, if you have some kind of truthy-or-falsey producing thing...like ANY or ALL or PARSE, it's a good candidate for OR. It can improve flow and readability, consider:
unless parse skip executable e_phoff [
e_phnum [
(mode: 'read) pos: program-header-rule
(if p_offset >= offset [p_offset: p_offset + delta])
(mode: 'write) :pos program-header-rule
]
to end
][
fail "Error updating offsets in program headers"
]
This starts looking a little better when OR is used:
parse skip executable e_phoff [
e_phnum [
(mode: 'read) pos: program-header-rule
(if p_offset >= offset [p_offset: p_offset + delta])
(mode: 'write) :pos program-header-rule
]
to end
] or [
fail "Error updating offsets in program headers"
]
For starters, it's a little shorter. But more importantly, it lets PARSE stay at the forefront so this line of code looks primarily like a parse operation, as opposed to an unless operation. The infix OR helps contextualize things later, more than just seeing an unadorned block. You don't have to mentally track whether it was an IF or an UNLESS when you're reading at that point.
ELSE is for interacting with the outcome of conditionals, where the desirability of being able to return blanks or false is just too high:
flag: if condition [
false
] else [
true
]
This couldn't work with OR, because it would assume the successful condition check which produced FALSE would require triggering the next branch, and returning TRUE. So IF returns void when its condition fails, as a cue to tell ELSE that it should run. But more generally, it's useful for making a failed conditional "opt out".