Why shouldn't VOID be done with a ~void~ WORD! Antiform?

I might as well throw in the adjunct question of: "Why shouldn't VOID be done with ~void~ antiform?"

It used to be said of NULL that it had "no representation". That's true of antiforms also, but there's been a standard that the interface shows an antiforms by printing the quasiform and then commenting it as "oh, it's actually an antiform state"

At that time, the console had a special exception for displaying nulls. And the "quoted" form of null was just a single apostrophe with nothing after it:

>> null
; null

>> quote null
== '

>> '
; null

This was all conceived before the idea of having a meta state for void, because voids just vanished. But as things shuffled around, I came to think that this "no representation" made more sense for voids...

>> '

>> quote void
== '

>> meta void
== '

Having a META state that is quoted vs. quasi puts VOID in a bizarre middle ground of not being an antiform. Yet void can't be put in a block. Though I've argued that we might also see it as that you can put infinitely many voids in a block...

>> append [a b c] '
== [a b c]

 >> append [a b c] if false ['d]
 == [a b c]

 >> first []
 == ~null~  ; anti

 >> append [a b c] first []
 ** Error: Can't append ~null~ antiform (see MAYBE)

 >> maybe first []

 >> append [a b c] maybe first []
 == [a b c]

Generally speaking I'm pleased with that. Though it means if you wind up setting a variable to void, it will look kind of slight:

 >> make object! [x: comment "hi"]  ; might require a SET/ANY or similar
 == make object! [
     x: '

Why not push ithe other way, and say that voids are antiforms?

One key value of saying that void states are "ordinary" is that it means they have an isotopic form, and that isotopic form is rendered as just ~.

This isotopic void state of ~ is being used as the "truly unset" state. An even meaner idea of complete absence of value than void. I'm of the belief that it's important to have this not be the same thing as void, because the tolerance of void by so many constructs (including things like ANY and ALL to skip them, or opting out of APPENDs, or making SELECTs just return a null).

The design of the system is such that the quote byte of 0 means isotopic status (e.g. "quote level negative 1" is represented by 0), and the void type is a 0 byte. So you can memset() an area to 0 and get all unset states (typically an optimized operation). And the operating system clears all memory to 0 before giving it to your application as well. It's kind of pleasing that such a representation gives you a nice unset state.

It seems to me that the pieces of the puzzle fit together better this way.


So as it turns out, you can get all the same benefit here if ~ is the anti/quasi form of BLANK!.

(There's no particular reason it should have to render as ~_~, and that looks terrible anyway.)

To the extent this matters, you could get all the same benefit here if BLANK! is the 0 heart byte. (The 0 byte is probably used for other purposes.)

Real Answer: It should be.

It's become apparent that as a practical matter, void's status as "not an antiform, not a regular value either" is a thorn in usage and implementation.

  • It complicates checking for when you're putting illegal states into cells that the type system has declared are "safe for blocks". You can't just check for the quote byte being -1 for an antiform. You have to check for quote byte 0 and heart byte of void as well.

  • It means that if you're trying to put a void in suspended animation, your suspended state is a plain quoted value. But there's a function I need which I've been calling DEGRADE which changes all quasiforms into their antiforms, passing through everything else. The need to degrade voids is common, and it means degrade would have to break the pattern... taking in a non-quasiform (a quoted) and returning a non-antiform (a void).

  • The isotopic era solution to a "weird" thing to put in the typecheck specs for NULL is [~null~ integer!], instead of [<opt> integer!]. That's a nice solution to a longstanding problem of wanting to make nulls stand out, leaving tags free for other things. But the trick couldn't supplant [<void> integer!] because that would come out looking like [' integer!] ... which is no good, and again the problem of a different "part of speech".

  • A single tick mark is pretty slight visually for an element you can put in blocks. The "chunkier" representation of voids as ~void~ vs. being absolutely invisible may feel a bit strange for something that intends to vanish, but in the world of isotopes... all antiforms are abstractions with no actual representation. It's just a concept, and having the concept be a full English word has advantages in handling and comprehension.

Hence, a "Minor" but Important Change...

  • VOID is a WORD! quasi/antiform, ~void~

  • TRASH is the BLANK! quasi/antiform, ~

This ties in with finalizing one can hope another decision: to make the console treat trash invisibly, but show voids.

>> if false [<something>]
== ~void~  ; anti

>> meta if false [<something>]
== ~void~

>> unset 'x

>> get/any 'x

>> meta get/any 'x
== ~

Implementation-wise it doesn't change a lot...but what it does change is pleasing and simplifying.