The concept of having isotopic ~true~ and ~false~ as WORD! isotopes instead of having a distinct LOGIC! type is admittedly somewhat weird. It means they can't be put in blocks and need some sort of transformation if they're going to be put into blocks.
-
The generic and reversible way to make them real it is to META them and get
~true~
and~false~
quasiforms, which you can UNMETA back to the isotopes -
The readable way to make them real is to REIFY them and get
true
andfalse
as plain WORD!, which only gets turned back into the isotope form if they are bound to variables that hold the isotopes, and you evaluate them. -
Your circumstance may mean that neither of those choices are what you want when in a situation where the isotopes can't work...maybe it means you have to rethink what you're doing, or maybe you want some other transformation. It's good to be alerted to the fact that it's dodgy to put what you think of as a "logic" in a reified context.
One should note that Lisp has no false at all, only NIL for false (since everything else is truthy, you could use anything else for true, but they have T predefined). But their NIL isn't isotopic--so it can appear in lists literally.
And as I've repeatedly pointed out, Redbol's historical choice to render LOGIC! conflated with the words true
and false
(instead of #[true]
and #[false]
) shows a desire to avoid the logic literals "escaping" into the reified consciousness of the user. Making the logic forms actually impossible to put into blocks without a conscious transformation feels like it's good.
I know it's a strange choice, but it's seeming like it fits with the territory. It's a sort of tradeoff you need when you choose to be firm that TRUE and FALSE are redefinable words and not lexical forms of logic constants.
So... Why Shouldn't NULL Be Done With ~null~
isotope ?
Right now what I call "null" is isotopic BLANK!. It is not pretty looking:
>> null
== ~_~ ; isotope
>> _
== ~_~ ; isotope
But what is pretty looking is that if you assign a bunch of variables to null, the fact that blanks evaluate to the null isotope gives a great visibility to where the actual values to pay attention to are:
obj: make object! [
alpha: _
beta: _
delta: true
epsilon: ~
gamma: "nutty"
rho: _
omega: 'now
]
If we used a word isotope, then at source level we're writing:
obj: make object! [
alpha: null
beta: null
delta: true
epsilon: ~
gamma: "nutty"
rho: null
omega: 'now
]
And if we view it after evaluation that fetches (null
=> ~null~ ; isotope
), it gets uglier:
make object! [
alpha: ~null~
beta: ~null~
delta: ~true~
epsilon: ~
gamma: "nutty"
rho: ~null~
omega: 'now
]
We can't show it as the WORD! null because there's no guarantee that word always will evaluate back to the null isotope. But the concept is that since BLANK! can't be redefined, we can put it in an evaluative context as a substitute for ~_~
if we want.
If we were "more honest" and just META'd the isotopic blank, we'd get renders like:
make object! [
alpha: ~_~
beta: ~_~
delta: ~true~
epsilon: ~
gamma: "nutty"
rho: ~_~
omega: 'now
]
But I might actually like that less than seeing ~null~
there.
Things To Weigh In This Consideration
I'm really torn. Certainly having people be able to see ~null~ written out as a word corresponds to what we want to refer to the state as. We aren't going to replace people's vernacular to say "isotopic blank" instead of null. And trying to teach people "isotopic blank is null" is an uphill battle.
Let's look back at that seemingly beautiful situation with all the blanks-to-nulls at source level:
obj: make object! [
alpha: _
beta: _
delta: true
epsilon: ~
gamma: "nutty"
rho: _
omega: 'now
]
But, hmmm. The ~
is now an assignable state meaning variable is not set. How often will you want to set something to NULL...which won't generate an error on access like being unset would, but is falsey and can't be passed to many routines without a MAYBE?
Statistically, we might often have a situation where NULL is the minority initialization, more like this:
obj: make object! [
alpha: ~
beta: ~
delta: true
epsilon: null
gamma: "nutty"
rho: ~
omega: 'now
]
My point is that intentionally initializing things to null may not be as common as setting to an error-provoking unset state. And when null happens it may be just as noteworthy to call out as setting something to true or false.
Are There Technical Barriers To This?
It has some of the same problems as having to deal with the type checking of LOGIC! actually being an isotopic subclass of two words. It means <opt>
is an isotopic subclass of one word, so there's no specific null datatype. :-/
I was already saying that TYPE OF NULL was probably an error, and TYPE OF MAYBE NULL would be void... anyway, this fits into some of the same type issues that logic has.
Previously NULL cells held nothing, so I'd put a payload of the file and line that were in effect in the evaluator. This was supposed to give better errors about where a null originated from. This could still be done if NULL was a special case of WORD! isotope that said it was null via a flag vs. storing the symbol, but could be complicated. None of the better error mechanics were done yet.
My general intuition is that from a user's standpoint, it's an uphill battle to teach them isotopic blank is something called "null"... and that the majority of technical problems that are involved in making NULL be a word isotope are problems that have to be tackled anyway with true and false as word isotopes.
Additionally, I've written about my desire for BLANK!s to serve in dialects as spaces. That gets very screwed by the (_
=> ~_~
; isotope) evaluation. Recovering blank for space intent would be good.
I'm going to likely give it a shot, when I get some programming time again, hopefully soon.