What Are NULL, VOID, NONE, and TRASH ?

F.A.Q.

How Did These Types Evolve From Rebol2 UNSET! + NONE! ?

See this thread.

Isn't It Simpler to unify empty-PACK! and TRASH! as UNSET!, like Rebol2?

One can reasonably ask if when all is considered, having fewer parts is better--even when more parts can be shown to have "a benefit here and there".

So this does hinge on how you feel about things like:

rebol2>> compose [a (print "b") c]
b
== [a c]

Personally I see too much downside to conflating "meaningless" values with "meaningful opting out". While you might be able to make excuses for an oversimplified example that's just PRINT like this one, when you imagine a more complex expression, an error is far preferable. And it gives you the room in the future to start giving back meaningful values, without breaking people's depending on the not-very-intentional opt-out behavior.

So in Ren-C you have to erase the trash value, with something like:

>> compose [a (elide print "b") c]
b
== [a c]

But another aspect is that as TRASH! became an antiform of any RUNE! (so not just ~ as the antiform of space rune), the messages became useful:

>> var: ~#[some message]#~
== ~#[some message]#~  ; antiform (trash!)

>> var
** Error: var is TRASH!: ~#[some message]#~

This turned out to be very useful.