These are important "antiforms" you need to know about. (Antiforms can be held in variables, but cannot be put into lists like BLOCK!).
TRASH! is the antiform of RUNE!
Trashes are used to poison variables so they cause errors on WORD!-access
>> x: ~ ; no console output is printed for trash
>> x
** PANIC: x is TRASH! (~)
The simplest form of trash is the antiform of the space RUNE!. Its meta-representation is a quasiform shown as a lone tilde (~), which you can call "quasi space" or "quasi blank" if you like (I also call it a "quasar"). So evaluating quasiform space gives you antiform space, e.g. TRASH, which has no representation in the console.
>> quasi _
== ~
>> quasar? first [~]
== ~okay~ ; anti
>> ~
>> trash? ~
== ~okay~ ; anti
Operations like comparison functions do not accept unset states... as in Rebol2:
rebol2>> #[unset!] = 1
** Script Error: Cannot use equal? on unset! value
ren-c>> ~ = 1
** Error: VALUE1 argument of EQUAL? is unspecified
NONE is an Empty Splice, the "positive" sense of NULL
>> none
== \~()~\ ; antiform (splice!) "none"
>> append [a b c] none
== [a b c]
It's truthy, but comes in handy in places you want to "opt in" to an operation with nothingness.
VOID is the unstable antiform of COMMA!
VOID is another name for the GHOST! antiform... a "ghostly" intent--with no stable value to offer, hence cannot be decayed. There's also a "heavy void" which is the behavior of an empty parameter PACK!, for when you want to convey no value but not vanish.
GHOST! vanishes in REDUCE, and act as a no-op for things like APPEND.
VOID is the "result" of eval []
>> eval []
== \~,~\ ; antiform (ghost!) "void"
>> ()
== \~,~\ ; antiform (ghost!) "void"
It vaporizes in COMPOSE/etc.
>> compose [a (if 10 > 20 ['b] else []) c]
== [a c]
>> reduce [1 + 2, if 10 > 20 [<nothing>] else [], 10 + 20]
== [3 30]
>> append [a b c] ()
== [a b c]
>> if 10 > 20 ['b] else []
== \~,~\ ; antiform (ghost!) "void"
While VOID and HEAVY VOID have similar behaviors, only VOID represents a "vanishing intent" in multi-step operations. Understanding the subtlety of the distinction--and how the system protects you from accidental vanishes--is explained elsewhere:
https://rebol.metaeducation.com/t/why-comment-vanishes-but-not-eval-of-comment/2563
NULL is the antiform of the WORD! "null".
In the API this is represented as the 0 pointer and does not require having its handle released, so it is like C's NULL. It is used as an "ornery nothing"...but unlike TRASH it can be fetched by normal WORD! access. The system accomplishes elegant error locality using the VOID-in-NULL-out protocol in many places, which hinges on the OPT function that converts NULL to VOID.
>> case [1 > 2 [<a>] 10 > 20 [<b>]]]
== \~null~\ ; antiform
>> reduce [1 + 2 case [1 > 2 [<a>] 10 > 20 [<b>]]] 10 + 20]
** Error: can't put ~null~ antiforms in blocks
>> reduce [1 + 2 opt case [1 > 2 [<a>] 10 > 20 [<b>]]] 10 + 20]
== [3 30]
>> third [d e]
** Script Error: cannot pick 3
>> try third [d e]
== \~null~\ ; antiform
>> append [a b c] try third [d e]
** Error: Cannot put ~null~ antiforms in blocks
>> compose [all your base (try third [d e]) are belong to us]
** Error: Cannot COMPOSE ~null~ antiforms into slots
>> opt third [d e]
== \~,~\ ; antiform (void!)
>> append [a b c] maybe third [d e]
== [a b c]
To Sum Up...
-
TRASH is used to poison variables
-
It is neither logically true nor false
-
When you reference a variable containing trash using WORD!, it will cause an error
-
It's the typical choice of return value for functions with no meaningful result
-
The console displays nothing when trash is the evaluative product
-
-
VOID is intentional emptiness--tolerated many places as meaning "I'd like to opt out please"--and it vanishes in some places It comes in a "light" vanishing form (antiform COMMA!) and a "heavy" form (empty antiform PACK!)
- Since these opt out of aggregate conditional tests, they can't logically be acted on in an isolated conditional expression like IF
-
NULL is a signal, often meaning "I couldn't find what you were looking for"
-
Because it is a kind of "soft failure", it is the (only) conditionally false value
-
Also because it is a soft failure, most non-conditional slots reject it as an argument
-
OPT can be used tactically to convert NULL results to VOID
-
NULL and TRASH are stable antiforms... they can be held in normal variables, but won't be found in lists like BLOCK!.
VOID and HEAVY VOID are unstable antiforms, and can't be saved in normal variables--only meta-variables.