Does it really add value to consider the nothing state (an antiform blank held by unset variables) to be neither truthy nor falsey?
Here's a quick survey of how UNSET! (the most nothing-like thing in historical Rebol) is handled:
Rebol2
rebol2>> either get/any 'asdf [print "truthy"] [print "falsey"]
** Script Error: either is missing its condition argument
rebol2>> unset? all [get/any 'asdf]
== true
rebol2>> unset? any [get/any 'asdf]
== true
rebol2>> case [get/any 'asdf [print "truthy"]]
** Script Error: Block did not return a value
R3-Alpha
r3-alpha>> either get/any 'asdf [print "truthy"] [print "falsey"]
** Script error: either does not allow unset! for its condition argument
r3-alpha>> unset? all [get/any 'asdf]
== true
r3-alpha>> unset? any [get/any 'asdf]
== false ; ...huh?
r3-alpha>> any [get/any 'asdf 1020]
== 1020
r3-alpha>> case [get/any 'asdf [print "truthy"]]
** Script error: block did not return a value
Red
red>> if get/any 'asdf [print "truthy"]
truthy
red>> either get/any 'asdf [print "truthy"] [print "falsey"]
*** Script Error: block did not return a value ; <-- huh?
red>> unset? all [get/any 'asdf]
== true
red>> unset? any [get/any 'asdf]
== true
red>> case [get/any 'asdf [print "truthy"]]
*** Script Error: block did not return a value ; <-- huh, again?
Oldes Rebol3
Transparent in ANY and ALL (like a Ren-C void), but presumably still an error in plain IF or EITHER or CASE...
Ren-C's "Always Error" Has Been More Consistent, But...
Clearly people have been pushing away from it being an error.
So does being "ornery" for conditional logic really help matters? When we consider the dual role of nothing as an "uninteresting, but successful" result, might we get as much (or more?) value from considering it to be always truthy?
For example: Ren-C uses NOTHING as the result of PRINT when the print actually produces output. Otherwise, you get NULL.
>> message: "Hello"
== "Hello"
>> print message ; won't have a console "==" due to being a nothing result
Hello
>> nothing? print message
Hello
== ~true~ ; anti
>> message: null
== ~null~ ; anti
>> print maybe message
== ~null~ ; anti
>> print []
== ~null~ ; anti
Nothing has the property of suppressing console output, which is desirable in most print cases--at least those that do print output. And if you said (x: print "Hello")
you'd get a variable that would create an error on access, which seems also desirable.
If nothing was truthy, that makes it easier to act on the nothing-vs-null distinction in something like an ANY or ALL construct.
Should "Meaningless but Truthy" = "Unset Variable State"?
A related question may be if functions like PRINT should be returning the same value as what is held by an unset variable.
Now that non-antiform BLANK! itself is truthy, might it be a better choice?
>> print "Hello"
Hello
== _
But then...
-
For the visual we seek, the console would need to not print BLANK!. But I find it unsatisfying to have a non-antiform be what has "no representation".
-
If you assigned the result of this "meaningless" value to a variable, you wouldn't have that added protection that the variable would appear unset.
Truthy Nothing Seems To Have More Pluses than Minuses
My "semantic safety" bias initially had made me think that when you have a function like PRINT, it's nice to catch potential mistakes when you tried to act like it was a function that could meaningfully be tested for some kind of logical result. So I pushed R3-Alpha's error from IF and EITHER further into ANY and ALL.
Then I went and made it so that when the PRINT received an opted-out input, it gave back NULL instead of NOTHING. So it was something you could act on with ELSE, but not other conditional constructs.
The evolution from UNSET! to the blank-antiform that is today's NOTHING has been a long and winding one. Working around its ornery-ness gave rise to all kinds of interesting designs like voids, and invisibles like ELIDE PRINT.
But though I'm sure that I haven't considered all the angles yet...having nothing be neither-true-nor-false is looking more like a dying historical artifact than something with a clear motivation applicable to the present.
Nothing being always truthy offers consistency...and it's possible to ELIDE it to get "no vote" so it won't affect an ANY or ALL (the way Oldes R3 treats unsets). Yet having the vote isn't entirely useless either. I can't think of a whole lot of downside, so I think it's worth trying.
A better axis of orneryness that may actually catch more problems in practice is: Should Nothing be Illegal in Comparisons
(I point out in that discussion that simply disabling the ability to check nothing for truthiness/falseyness is kind of a strange counterpart to a routine that returns--say--an INTEGER! in all cases, where you get zero information from testing an integer conditionally but without anything to stop you...making the disablement of testing nothing conditionally seem like a fairly empty gesture.)