I can argue pretty strongly for all the behaviors as being shades of distinction that are important.
I'll mention that I just addressed a weakness, which was that VOID didn't have a "good" representation in a block that identified it in the class of "weird states". e.g. it didn't have a quasiform. Now it does.
This means these are your stock "reified" options for shades-of-nothingness:
[name: "Thing" link: _]
[name: "Thing" link: ~] ; ~ is "quasi-blank" a.k.a. "trash"
[name: "Thing" link: ~null~]
[name: "Thing" link: ~void~]
It's the clear design rule now that all of these forms are inert (when accessed via word) and truthy--everything you can put in a block is.
But each of these forms have different behaviors once you evaluate them (or DEGRADE them, e.g. degrade fourth [name: "Thing" link: ~void~] narrowly turns the quasiforms to antiforms without doing any transformation of other types):
>> x: _
>> print either x ["truthy"] ["falsey"]
truthy
>> append [a b c] x
== [a b c _]
>> x: ~
>> print either x ["truthy"] ["falsey"]
** Error: x is not set (~ antiform), see GET/ANY
>> print either get/any 'x ["truthy"] ["falsey"]
truthy
>> append [a b c] x
** Error: x is not set (~ antiform), see GET/ANY
>> append [a b c] get/any 'x
** Error: APPEND expects [~void~ element? splice?] for its value argument
>> x: ~null~
>> print either x ["truthy"] ["falsey"]
falsey
>> append [a b c] x
** Error: APPEND expects [~void~ element? splice?] for its value argument
>> x: ~void~
>> print either x ["truthy"] ["falsey"]
** Error: ~void~ antiform is neither truthy nor falsey
>> append [a b c] x
== [a b c]
So...I'm afraid that BLANK!'s relationship to nullness and falseness has basically gone away. Instead, it's the "space unit" of BLOCK!s--the moral equivalent of a space character in a TEXT!.
BLANK! has important uses that make it good to be a non-reassignable unit type, taken away from WORD!. Crucially it now provides the heart of the nothing antiform to represent unset variables--using a similarly light-looking antiform/quasiform of ~
("trash").
Also, I've mentioned its application in PATH! and TUPLE!:
>> to path! [_ x]
== /x
>> to path! [x y _]
== x/y/
...as well as in multi-returns:
>> [_ @end]: find "abcdef" "cd" ; opt out of main find result, just get tail
== "ef"
>> end
== ef
Having it be out-of-band and not a WORD! is a strength in these areas.
I do think that having SPREAD of a BLANK! return a VOID or an empty splice is probably a good thing... though not completely sure on the merits of choosing one over the other. An empty splice may be "more coherent" in the sense that one probably wouldn't want foo spread _
to give back null if foo spread []
would not. Considering it "EMPTY?" in certain contexts may be appropriate as well...but not falsey.
A year down the road here, things are clicking in place. Though it would have been massively helpful to have a time machine and send a few of these posts a few years back. I'm patching a bootstrap executable to be compatible with many of the conventions, and it's pretty quick work when you know what the decisions are.
(I was just watching a video laying out the difficulties in creating the blue LED (recommended)... and it's so comprehensive on semiconductor technology that sending that one video back in time would have radically changed the course of history.)
I've got a pretty solid sense that the best substrate comes when everything you can PICK out of a block is inert and truthy, where this kind of thing holds:
backup: copy block1
block2: copy []
while [value: try take block1] [ ; you can also shim TAKE as synonym for TRY TAKE
append block2 value
]
assert [block2 = backup] ; always true, for any and every BLOCK! (GROUP!, etc.)
So it's upon you--the interpreter of the block--to give it meaning. If you want to know if something is blank, you say BLANK?. If you want to DEGRADE things, you do that.
I've surveyed the most code written by the most people...and maintained giant systems after those who wrote them wandered off. And I've tried a lot of things. What it's converging on is what I believe to be the best direction for this medium.
But the proof should be in your code, as well. I've held off on advocating people spin their wheels porting scripts while things are in flux, but as the flux diminishes I think it's worth it to do some porting of key Rebol2 scripts and document the experience.
A little more work on binding first... but... the time is coming.