A Justification of Generalized Isotopes

If Isotopes Are So Great, Why Don't Other Languages Have Them?

In a way, Rebol2 had some inkling of isotopic ideas with errors. Because an ERROR! couldn't be fetched from a WORD! without triggering an exception...you'd have to DISARM it, and that would convert it into an OBJECT!.

Early on when I was looking at the language, I did wonder if functions should have an "armed" vs. "disarmed" state--like errors. This arose while trying to generate C code which assigned function variables...kind of along these lines:

r3-alpha>> do compose/only [append-alias: (:append)]
; How to stop APPEND from running, by changing *only* inside the (...) ?
; (and still make APPEND-ALIAS act as a synonym for APPEND)

r3-alpha>> do compose/only [append-alias: quote (:append)]  ; QUOTE meant THE
; this is all you could do, but you had to manipulate the enclosing
; template...the slot itself couldn't "meta" the state for eval

I talked myself out of it at the time...because I worried about "hidden bits" like the armed state. But after years of building on incremental ideas like generic quoting, there are answers to such historical problems. You can put a quasiform in that slot and it can evaluate to the antiform (itself having no representation, and can't be put in blocks, stopping the spread of this "invisibility").

But why didn't a parallel concept evolve in Lisp or other languages? Here are some thoughts on reasons...


Lisp's quoting is a rendering trick on its list structures, there's not an actual place to store a negative quoting level.

Antiforms are tied in closely to the concept of generic quoting, and I've kind of said that they're akin to "having a quoting level of negative one".

One thing that would hold Lisp back from seeing this as a natural possibility is that there isn't actually a "quoted value type". When you see quotedness, it's just a rendering trick. Something along these lines:

lisp>> (print "Hi")
"Hi"

lisp>> '(print "Hi")
== (print "Hi")

lisp>> (quote abc)
== abc

lisp>> '(quote abc)
== 'abc

lisp>> '(quote (quote abc))
== ''abc

lisp>> (type-of '(print "hello"))
== cons  ; something like "group!"

lisp>> (type-of '''abc)
== cons

On the plus side of not building quote levels into the cells themselves, they can use the existing flexibility of lists to get arbitrarily high levels of quoting. (Right now Ren-C mechanics only allow 127 quote levels.)

But you can see how this would create a pretty big barrier to coming up with an idea like "negative quoting"; it would seem to make no sense.

Also: Like in Ren-C, if you evaluate a quoted structure in Lisp you drop one level of quoting. But they didn't think it worth it to put an UNQUOTE in the box as a narrowed form of EVAL that only took quoted structures. Without that, one wouldn't be likely to think of wilder things like UNMETA.


Lisp's focus on compilation means they wouldn't like the idea of things like runtime conversions of normal values into states that would make a variable act undefined.

This kind of fits in with the fact that a lot of things Rebol does would be off the table for many Lisp implementers.

For instance: Lisp dropped the idea of being able to mark a function's arguments as being quoted at the callsite, because of how much that interferes with compilation:

"The idea of first-class operative combiners, i.e., first-class combiners whose operands are never evaluated, has been around a long time. Such creatures were supported by mainstream Lisps through the 1970s, under the traditional name fexprs, but they made a mess out of the language semantics because they were non-orthogonal to the ordinary variety of procedures constructed via lambda — and, more insidiously, because at that time the mainstream Lisps were dynamically scoped (a language feature that causes more problems for fexprs than it does for the less powerful macros)."


Most Languages Use Containers

I've done a writeup of Haskell's Either and Rust's Result, showing some of what's similar about them to isotopes:

Haskell and Rust Error Handling

There are actually a fair number of nuances, but antiforms are kind of like a container that's available system-wide on every variable... but not array slots.

And because it's systemic and built in, you don't have to think about this containership in advance. Look at what it takes to return an Either from some sample Haskell code:

parseDigit :: Char -> Either ParseDigitError Int
parseDigit c =
  case c of
    '0' -> Right 0
    '1' -> Right 1
    '2' -> Right 2
    '3' -> Right 3
    '4' -> Right 4
    '5' -> Right 5
    '6' -> Right 6
    '7' -> Right 7
    '8' -> Right 8
    '9' -> Right 9
    _ -> Left (NotADigit c)

The isotope model is more like letting you say ('0' -> 0) and (_ -> raise NotADigit c), so you only have to call out the "weird" cases.

Though there's no truly silver bullet: if you're exchanging reified data via arrays, you can't use antiforms there. So the convention of "containership" has to be decided on in advance for fully generic code. (If the code isn't fully generic and you aren't using quasiforms for something else, then the QUASIFORM! can serve as a means of tunneling antiform intent...see REIFY+DEGRADE vs. META+UNMETA)


It turns out to be actually really hard to tie these concepts together coherently, and people who undertake such challenges usually wouldn't bother with a runtime model as informal as a Redbol's.

Newcomers to non-rigorous languages like JavaScript will often ask questions along the lines of "hey, why does JavaScript need both null and undefined". This triggers a lot of conversation about the various practical problems that would happen if you only had one or the other, and usually people throw up their hands and say "what's done is done" and get on with their lives.

A much rarer question would be: "might null and undefined be related in some transformative way, where certain basic operations naturally coerce and promote/demote between them in a meaningful pattern". Because that's a sophisticated academic way to think, and people who care about that use "better" languages. :face_with_monocle:

While someone might suggest this means the isotope design is thus a case of polishing a turd, my recent forays into Rust are reminding me of the unusual and distinct strengths that Ren-C has. I'm withholding my verdict on whether its future is more than a kind of educational video game, but I think it's at least that... so making the design "click" where it can feels worth it.

2 Likes