At the moment, not all isotopic states have meanings.
It is likely the case that you should be disallowed from creating ones that don't have meanings, to reserve them for future use.
(For lack of a better name these are called ISOWORDs for now.)
I wrote about the boolean design in a separate post.
It may be that these are narrowed to only a small set of choices reserved by the system like ~null~, ~true~, and ~false~... and if you want a generic error-trigger (like a labeled unset variable) that would be something else, like an isotopic tag.
Yes, isotopic VOID is now called TRASH, and used for unset variables.
(If you find posts with outdated naming let me know--just leave a reply citing the problem and I will fix it up.)
Non-isotopic frames don't trigger execution via word reference, are easier to pass around and manipulate.
>> f: make frame! :append
>> f.value: 10
>> append10: isotopic f
>> append10 [a b c]
== [a b c 10]
A non-isotopic frame--by virtue of not being isotopic--can appear literally in a block and the evaluator will run it when encountered, without the need for a word reference to trigger it.
>> do compose [(f) [a b c]]
== [a b c 10]
Due to this design, enumerating blocks will not accidentally run functions, the way historical Rebol and Red will:
rebol2>> foreach item compose [(:append) (:insert) (:change)] [
if action? item [print "it's an action"]
]
** Script Error: item is missing its value argument
...since only isotopic actions run via word reference, and there are no isotopes allowed in blocks.
NIHIL is the name for the special case of isotopic BLOCK!, which is a parameter "PACK". It's simply an isotopic block with no values in it.
I've mentioned previously that packs are the basis of multi-return values, but if a situation is not sensitive to multi-returns then they will decay to their first element.
>> x: ~[1 2]~
== 1
>> [x y]: ~[1 2]~
== 1
>> x
== 1
>> y
== 2
>> append [a b c] ~[1 2]~
== [a b c 1]
As an example of the usage of multi-return values, consider FIND.
>> find "abcdefghi" "def"
; first in pack of length 2
== "defghi"
>> pos: find "abcdefghi" "def"
== "defghi"
>> [pos end]: find "abcdefghi" "def"
== "defghi"
>> end
== "ghi"
NIHIL being zero values cannot be used in an assignment, but if it's between expressions it will vanish.
>> 1 + 2 ~[]~
== 3
This is used as the return value for things like COMMENT and ELIDE.
Isotopic commas (like isotopic frames) cannot appear in blocks, so certainly different in that respect.
A non-isotope comma evaluates to an isotopic comma, which the evaluator discards... leaving the previous result:
>> meta ,
== ~,~
>> length of [10 + 20,]
== 4
>> 10 + 20,
== 30
It's similar to NIHIL in this respect. At one point COMMA! just evaluated to NIHIL but some problems were encountered with that, which I explain in the post you linked.
Isotopic ERROR! is a "Raised" Error
If you look at exception handling in Rebol and Red, it is extremely brittle. Their constructs will basically intercept any failure that occurs at any level in the enclosed code... including typos:
As a very simple example:
red>> attempt [data: read http://example.com]
== {<!doctype html>^/<html>^/<head>^/ <title>Example Domain</title>^/^/ ...
red>> attempt [data: read http://xaasdfaefafa.com]
== none
red>> attempt [data: readd http://example.com]
== none
So there's no real way to narrow intercepting errors that are a result of a specific call. Ren-C uses error isotopes to do this... where you can't store error isotopes or pass them most places, but special constructs like TRY and EXCEPT can handle them.
e.g. TAKE returns an error isotope when you try to take from an empty block. By default this will be "promoted to failure":
>> take []
** Script Error: Can't TAKE, no value available (consider TRY TAKE)
But before that promotion to failure (which can only be intercepted by SYS.UTIL.RESCUE), you can meta a raised error at the moment it is returned from a specific call:
>> meta take []
== ~make error! [
type: 'Script
id: 'nothing-to-take
message: "Can't TAKE, no value available (consider TRY TAKE)"
near: [meta take [] **]
where: [take console]
file: ~null~
line: 1
]~
As it suggests, TRY will convert raised errors to null:
>> try take []
== ~null~ ; isotope
Original writeup here:
FAIL vs. RETURN RAISE: The New Age of Definitional Failures!
OBJECT! is the very experimental "LAZY"
This has turned out to be more of a rabbit hole than I first thought. I'm not sure if this is going to make it, but some experiments have been done with it:
Applications of Isotopic Objects
That's all the isotopes so far...