What If "DATATYPE" Was Isotopic (TL;DR: Bad Idea)

Hey. Waitasec...

...an unexplored idea here is if isotopic datatypes aren't just the "I mean match the datatype, don't look for it literally"... but what if it's more radical... to say that is what a datatype actually is.

In a nutshell, I'm saying this:

>> integer!
== ~@[integer]~  ; isotope

This would lean more heavily into the idea of isotopes that don't trigger errors when you fetch them out of words, and would require friendlier handling in things like equality operators.

Example Of Effects on FIND

With the current implementation you'd thus get something like the historical behavior when using plain INTEGER!, and then get different results out of looking for the REIFY or META forms:

>> find [a @[integer] ~@[integer]~ 1 b] integer!
== [1 b]

>> find [a @[integer] ~@[integer]~ 1 b] reify integer!
== [@[integer] ~@[integer]~ 1 b]

>> find [a @[integer] ~@[integer]~ 1 b] meta integer!
== [~@[integer]~ 1 b]

The De-reification Of "DATATYPE!"

So this would push our idea of what "DATATYPE?" is to being an isotopic THE-BLOCK! or whatever... in the same way that a SPLICE? is an isotopic group, and a PACK? is an isotopic block.

The "ugly-and-alarming QUASI!" form could be used to generate the datatype in a pinch:

 >> integer!
 == ~@[integer]~  ; isotope

 >> ~@[integer]~
 == ~@[integer]~  ; isotope

 >> switch type of 1020 [~@[integer]~ [print "It was an integer"]]
 It was an integer

But this kind of META/UNMETA would be a generic persistence tool that you'd reach for to be expedient. Generally speaking the expectation would be that your source-level dialects that needed to represent types would work with another form.

Downsides To Not Being Able to Put a "DATATYPE!" in a BLOCK?

We're talking about a situation where if you write something like:

reduce [1000 + 20 integer!]

You're going to get an error, because INTEGER! looks up to an isotope. How you deal with this would be up to you, and I guess it all depends on what you're going to do with the block later.

Maybe you're putting something together for a kind of type test in the future? You could leave the word around, either by quoting it or putting it in a BLOCK!, which is what is usually the mode of typeset representation in a dialect anyway:

>> reduce [1000 + 20 'integer!]
== [1020 integer!]

>> reduce [1000 + 20 [integer!]]
== [1020 [integer!]]

If you're trying to "boil away" the word and get at the underlying type--maybe because you want to do a type test with it and have the meaning persist even if the word lookup changes, you've got the options of reifying or of meta'ing:

>> reduce [1000 + 20 meta integer!]
== [1020 ~@[integer]~]

>> reduce [1000 + 20 reify integer!]
== [1020 @[integer]]

But the point is that these aren't the only options. You might have other ideas for what @ types do, and so you might want to construct something entirely different:

[1020 (<type> integer)]

However you'd need to get that transformed back before using it with FIND or a test against a TYPE OF. The point of the ~@[...]~ and @[...] is that they are within close reach when you don't have a reason to overthink it and those cases don't collide with anything.

Is This More Trouble Than Just DATATYPE!-Ends-In-(!)

As things get shuffled around it's good to stop and ask back from first principles what the point is.

One point of having an isotopic form of a datatype is so that there's some non-reified signal to pass as a parameter that indicates you want to match the type vs. to look for it literally...as with the FIND example.

This could be done another way--with refinements or signals--just as splicing can be controlled by something like /ONLY instead of letting the value carry it. But it's a neat feature that people had become attached to, and it's a kind of polymorphism that is pleasing.

That's part one...but then we can ask about the merits of this specific idea of having only an isotopic form.

There's the "representational greed" aspect--which basically says that if we can get away with having only an isotopic form carry the meaning of "datatype", the non-isotopic form becomes fair game for other things.

What's nice about this is that when I say:

 parse [1 2] [some integer!]

We're not giving anything up in the parse dialect box of parts related to @. And we're not messing with words like !!WARNING!! or any other idea that might involve exclamation points.

I mentioned the fact that it was "no accident" that things like #[true] and #[false] were rendered as just the words true and false... because people didn't want something that wasn't the words "leaking". I think that's true of the datatypes as well--it's a rare-if-ever situation that you want your mediums of exchange to have something gnarly like #[datatype! integer!] in them. So with the "you can't put it in blocks" alert, you get to have that moment of triage.

Fitting into the whole puzzle of isotopes means they're just a stone's throw away from having a stock representation...but you'll need a step to bring it back to being a "datatype" again.

2 Likes

Before I could give this a shot, I had to turn today's DATATYPE! (including extension datatypes) into something that just contained a symbol. I wrote that up in a separate post, to keep this one...uh...focused(?)

That first part went pretty well, it cleaned some things up!

Then I tried the datatype-is-always-an-isotope part...

:grimacing:

It Appears That Normalizing Isotopes Is Bad Mojo

To pick a big sticking point: I think I've decided I don't want there to be a TYPE OF an isotope.

  • Isotopes have no representation. They're the impressions left by the evaluation of a quasiform or unmeta of something that does have a representation.

  • Hence it feels only sensible to say isotopes have no types. Their types should also only be gotten by the impressions, e.g. type of ^isotope-var

If we don't do that, we get into problems of TYPE OF serving two masters. If it gets a parameter pack, is it supposed to say that it's the type of the first item in the pack... or is it supposed to tell you it's a pack? The ^META removes the ambiguity.

This led me to further realizations that it undermines isotopes in the system to have them accepted by common functions like =. So I think I'm leaning toward rolling back the clock on some of the encroachments isotopes were starting to make, and adjusting the terminology:

  • The quasiform ~(d e)~ would be a "splice!", and have a datatype (e.g. @[~group~] or similar)

  • The isotope of ~(d e)~ would be a "splice! isotope" and not have a type

  • So you would have to say if splice! = type of ^xxx [...] or if splice? ^xxx [...]

With things like = not accepting isotopes, that makes it pretty clear that whatever TYPE OF returns...e.g. whatever a "datatype" is...won't be something like "alias for THE-BLOCK! isotope". Because we don't want to be saying:

if ^integer! = ^ type of 10 + 20 [...]  ; obviously no.  just, no.

We Then Reserve Isotopes For Cool Features

This was the historical interpretation of INTEGER!

switch type of 1020 [
    integer! [print "Historically, we expect this to print"]
]

But I augmented that with a fun new behavior that was accomplished with MATCHES. Since the EQUAL? test would not accept isotopes as real things, you didn't have to worry that the isotopic datatype MATCHES created was being tested for equality literally...so it could take a more creative interpretation:

switch 304 [
    matches integer! [print "This would print, a cool new feature"]
]

We couldn't do that if INTEGER! was itself some isotopic form of another value, because it would have a meaning in EQUAL?:

>> equal? (type of 10) (type of 20)
== #[true]

But allowing you to compare isotopes has all kinds of other problems I've summarized (e.g. how do you compare isotopic blocks, a.k.a. "packs"? They decay to their first element.)

We Probably Need TYPE-XXX! (and a Rendering For Them)

So if "DATATYPE!" can't be an isotopic form of something like THE-BLOCK!, why couldn't it just be a plain THE-BLOCK! ?

I've written up why I like @[...] too much to do this with, but why &[...] might be all right to give up:

Arrays For Composite Types

So I think this means we're going to have TYPE-BLOCK!, TYPE-WORD!, TYPE-GROUP!, TYPE-TUPLE!, and TYPE-PATH!

There's a bit of a sticking point here, between the non-quoted case of word being represented as &word or &[word]... and which one of these two is what WORD! looks up to.

I think that for uniformity, saying that all TYPE OF answers come back as a TYPE-BLOCK! makes sense, and is the thing most people would expect. Then say that KIND OF is something you can only ask of nonquoted things.

>> type of first [a]
== &[word]

>> kind of first [a]
== &word

>> type of first [''a]
== &[''word]

>> kind of first [''a]
** Error: KIND can only be asked of nonquoted values

>> kind of noquote first [''a]
== &word

Should everywhere that supports TYPE-BLOCK! also have to support TYPE-WORD! ? I dunno.

>> did parse [1 1 1] [some integer!]
== #[true]

>> did parse [1 1 1] [some &[integer]]  ; imagine that (integer!: &[integer])
== #[true]

>> did parse [1 1 1] [some &integer]  ; no WORD! for just &integer in lib
== #[true]

It doesn't seem like a terribly important feature, and it would inhibit the use of &xxx as HTML entities in a dialected sense. But I don't know.

Honestly, This Isn't Too Far From What I've Been Thinking

I kind of thought this was what was going to have to happen, more or less.

The new angle was using isotopes for the FIND types of scenarios. So I think the solution peaks around here:

>> integer!
== &[integer]

>> matches integer!
== ~&[integer]~  ; isotope

>> find [a &[integer] 1 b] integer!
== [&[integer] 1 b]

>> find [a &[integer] 1 b] matches integer!
== [1 b]

I tried to weasel out of making TYPE-XXX!, but my weaseling did not work, and so I think this is going to be the answer.

1 Like