Console Treatment of VOID vs. TRASH (isotopic void)

Rebol2 and Red both have a console property that when the console sees an UNSET!, it prints nothing:

>> block: reduce [<a> #[unset!] <b>]
== [<a> unset <b>]  ; bad rendering, conflates #[unset!] with the word `unset`

>> first block
== <a>

>> second block

>> third block
== <b>

This doesn't provide the best grounding in the console, especially considering that in their world an UNSET! is a reified value that can be found in a block.

However, returning an UNSET! is how functions like PRINT avoid outputting anything with == in the console:

rebol2>> print "Notice no == result"
Notice no == result

rebol2>> type? print "Test"
Test
== unset!

But What Result Should Ren-C Suppress?

Ren-C has the concept of VOID which has an isotopic form known as "TRASH", that is used as the unfriendly contents of an unset variable.

For educational purposes, I feel it makes the most sense to have voids not print anything, and trashes print out the standard isotopic form:

>> void

>> quote void
== '

>> quasi void
== ~

>> ~
== ~  ; isotope

Looking at this, it might seem to make a lot of sense to have functions like PRINT and HELP return VOID.

But as I explain in "Why doesn't PRINT return VOID or NIHIL", there is a bit of a pitfall. Voids are friendly in terms of opting out of things:

>> append [a b c] print "If PRINT returned void..."
If PRINT returned void...
== [a b c]

This seems too friendly to me. There's another possibility of returning NIHIL, which would prohibit use as an argument It would wind up making an evaluation appear to be void if no other expressions were in play...but if other expressions were involved it would let them fall out

>> print "If PRINT returned nihil"
If PRINT returned nihil

>> append [a b c] "If PRINT returned nihil"
If PRINT returned nihil
** Error: APPEND is missing its VALUE argument

>> 1 + 2 print "If PRINT returned nihil"
If PRINT returned nihil
== 3

So returning TRASH feels like it makes the most mechanical sense...it has the right amount of ornery-ness:

>> print "Mechanically this works best"
Mechanically this works best
== ~  ; isotope

But it's ugly to have that == ~ ; isotope after every HELP or PRINT or other function.

Previously I had it so that trash printed nothing, and void printed out a comment:

>> ~

>> void
; void

But this is making the console pretty at the cost of obfuscation. I'll point out that the web console can make the == ~ ; isotope some kind of light gray so it's less noticeable.

People Always Bend To Get What They Want...

I might not like the idea of returning a "friendly" void to get invisibility, and try forcing everyone to use TRASH for console commands. But if they see VOID/NIHIL as the better way to get what they want, they'll choose that in their own commands to cut down on the clutter.

Perhaps there's a rationale here for why isotopic void would output nothing, while void would give a comment? If you consider the fact that isotopic void is "less than" a void, then giving it the special nothing-printed status makes some amount of sense, maybe. :thinking:

1 Like

I gave a demonstration of Rebol to the KYOSS Group yesterday, and had to sort of wince at that basic first-impression situation:

>> print "Hello"
Hello
== ~  ; isotope

It opens a can of worms right off the bat, by throwing the "isotope" term at people.

Though outputting nothing at all when you print is far from a universal expectation. Firefox and Chrome's JavaScript's consoles are explicit about returning undefined from functions like console.log:

 > console.log("hello")
   hello                       [VM146:1]
<- undefined

Clojure prints out nil:

=> (print "Hello World")
 Hello World
 nil

So utter silence doesn't seem like it's an expectation when you type PRINT. It's just that something about the ; isotope part that makes it unsettling to a first-time user. A simple ~ might seem okay by comparison:

>> print "Hello"
Hello
== ~

But that's just incorrect. We have to distinguish ordinary quasi-void from an isotopic-void somehow.

There could be a special rendering just for the none case, perhaps instead of ; isotope it could say ; trash

>> first [~]
== ~

>> do [~]
== ~  ; trash

>> print "Hello"
Hello
== ~  ; trash

That isn't much better, and probably does more harm than good in people's "isotopic education".

I can't avoid the fact that vaporization of PRINT makes me uneasy. I prefer making you write elide print. But it may be simply the correct choice from a marketing angle.

There are downsides to it, but there are also upsides. It means PRINT would go back to being unusable in assignments:

>> x: print "Hi"
** Script Error: No value in isotopic BLOCK! pack: ~[]~ (nihil)

But you'd be able to tack it on the tail of expressions:

>> x: (1 + 2 print "Hi")
Hi
== 3

Maybe more people consider that a feature than bug... @rgchris and @gchiu have repeatedly asked why can't PRINT vaporize instead of having to write elide print. I've been stubborn about resisting, but mostly because I don't want people to become too casual about making vaporizing functions...the fewer, the better. But I guess that's a point that just belongs in the documentation for NIHIL.

It's an immovable-object-meets-unstoppable-force situation...where I don't want to compromise the accuracy of the console, and I also don't want first impressions of the console to slap people in the face with confusion.

Yesterday's presentation convinced me. Vaporizing PRINT wins... NIHIL is the return value. (Until further notice, I guess.)