Clarity + Brevity vs. NULL, BLANK, NOTHING, VOID...

"I don't understand. There are just as many notes, Majesty, as are required. Neither more nor less." :slight_smile:


(2024 UPDATE: Here's a more modern and coherent layout of the design points.. Being able to edit the posts means I can make things look like they've always been that coherent--they certainly were not--if you want to see all the dead ends then join the Archivists group.)


Rebol2/Red/R3-Alpha all have basically two concepts: NONE! and UNSET!. NONE! and Ren-C's BLANK! were supposed to be quite similar, just a different name. But eventually NULL took over many of the duties of NONE! as an indicator of "soft failure" from a routine... like when a FIND can't find anything, or a conditional statement doesn't run any branches. BLANK! sticks around as the solution to the problem of neutral placeholders in blocks.

What's happened is that these two ideas (NONE!/UNSET!) have become at least five...depending on how you count, maybe more!

  • NULL has properties unlike anything in Rebol2. It cannot be put in a BLOCK!. It is a transitional state representing nothing, like how a C null pointer doesn't point to any memory. It is conditionally false if it appears in something like an IF statement, and it is the "soft failure" result indicating something didn't succeed e.g. a FIND that couldn't find what you were looking for, or a loop that BREAKs.

  • BLANK! is a unit type...e.g. a value of type blank holds no further information (than that it is of type blank). Unlike NULL it's something that can appear in a block, and hence can be used as a placeholder--for instance if a block represents a record structure broken into N-element units, it could represent a missing field. (Update: Values of this type were once conditionally false, but it was later deemed better if they were not.)

  • Today's idea of VOID -- as promoted by @rgchris -- is as the absence of a value. If you write append [a b c] void you will get [a b c] back (null would have given an error). Among other things, it is result of an IF that does not run its branch.

  • NOTHING replaces "unset" as the contents of an unset variable (in Ren-C's parlance, variables are unset, not values.). Like null and void (or any other antiforms), it also cannot be put in blocks.

  • NIHIL is an unstable antiform that can't be stored in a variable at all, but is a transient evaluative product discarded by the evaluator. It's tricky to handle, but gives neat properties to be able to erase evaluations from an execution stream, e.g. so 1 + 2 comment "hi" can synthesize 3.

I think the names have ultimately settled down to work pretty well. Particularly pleasing is that NULL is exposed in the API as C and JavaScript's NULL. That has turned out to be very important.

Rebol2 always had trouble with #[none]-the-unit-value and none-the-word, frequently rendering it as looking like the word:

rebol2>> find [a b c] 'd
== none  ; <-- not a WORD!, but a #[none] literal rendered dishonestly

As mentioned, Ren-C's find returns the ~null~ antiform now...which is better.

But reserving plain old _ so it's the literal form for a placeholder...and having it be named BLANK!...has felt pretty good. But we're still in that stretch of time for evaluating decisions for their merit...

3 Likes