As isotope design became refined, I became very pleased with the choice for what unset variables hold being the isotopic void.
>> x: ~
== ~ ; isotope
>> unset? 'x
== ~true~ ; isotope
The alternative of using the isotopic word ~unset~
was available. But isotopic voids are a particularly pleasing choice, due to their succinct representation...which helps assigned variables stand out better in lists of mostly-unset variables. And it's hard to think of what isotopic voids would mean if they were not the unset state!
Also, if ~unset~ were used then people would probably expect unset? ~unset~ to be true. But I've held pretty strongly to my general terminology:
"There is no such thing as an 'unset value'. But variables can be considered unset...when they hold a value that is an isotopic void."
I'm pleased with this and have almost no complaints.
The problem is that ISOTOPIC-VOID is a mouthful. It needed a short name.
JavaScript Don't Care
JavaScript went with the idea that unset variables hold "undefined", and you can test for it using the typeof operator to subvert the error that is raised on access for variables that are never declared (what we might think of as unbound):
>> typeof asdf == 'undefined'
<- true
But if you define a variable, then it will retrieve the undefined state without error:
>> let jkl
<- undefined
>> jkl
<- undefined
Whatever. Point is, they don't have any crisis of conscience on whether "variables are undefined, not values". They just go with it, as historical Redbol did with UNSET!.
But I don't like it.
TRASH Came To Seem The Best Option
"trash" isn't a new idea--I suggested it way back when the unset state was being changed away from being called VOID.
Inside the codebase I use the term "trash" to mean corrupting memory, e.g. setting pointers to 0xDECAFBAD so they'll generate errors if accessed in the debug build.
The concept of putting "trash" in a variable to disrupt accesses to it is kind of similar.
>> var: ~
== ~ ; isotope
>> var
** Error: var is ~ isotope
"Unset variables hold trash" comes across cohesively.
The more I thought about it, the more I liked it... because it kind of takes things a "notch up" from null. What's more ornery than a null? Something that's actually "garbage". In this way the pejorative sound of trash is actually kind of consistent with "hey, you can't reference that variable from a word because it's trash".
The initial roadblock I had was how jarring it might seem to people reading source for something that returns trash...which is the default prescribed return value when you don't have any specific idea:
foo: func [
return: [trash?] ; weird!
bar [block!]
][
append bar [a b c]
return trash ; also... weird!
]
But there's a reasonable answer in the modern type checking world for these cases which is semiotically consistent... use a tilde. The type spec accepts it (and assumes you mean an isotope), and RETURN will accept it (where the evaluator will turn the quasiform into an isotope):
foo: func [
return: [~]
bar [block!]
][
append bar [a b c]
return ~
]
As it happens, the default return result from functions is trash. I've also proposed it might be good to make the assumption that a function without a RETURN: spec is a procedure with no return result (as opposed to an unconstrained result).
foo: func [
bar [block!]
][
append bar [a b c]
]
You can still say return ~
or return trash
if you want in such functions if you want to return early.