The way antiforms were implemented originally didn't allow for the idea of giving a coherent answer back from TYPE OF. So they all gave the same answer, much how QUOTED! and QUASIFORM! all gave the same answer:
>> type of first [''a]
== &[quoted]
>> type of first [~a~]
== &[quasiform]
>> type of spread [a b c]
== &[antiform]
So there was nothing like &[splice]
. The only way to type check antiforms was with constraints, like SPLICE?... which was slower, since it had to call a constraint function.
But I reworked things in a way that speeds up SPLICE? to the point where it's no more expensive than checking for INTEGER! (or INTEGER?).
As a curious byproduct that I didn't even initially intend, this changed the behavior and it started treating antiforms as being datatypes:
>> type of spread [a b c]
== &[splice]
I was actually surprised, because I didn't intend to do it. It's not often a feature "just happens".
But Is It A Good Idea For Antiforms To Answer TYPE OF?
I've struggled with types, and the question of what TYPE means, vs. what KIND means... or CLASS?
If we develop some sort of class system, then TYPE becomes a loaded question. If you have an object that somehow remembers it was created as a BOOK!, then do you get book! = type of my-book being true? Or is TYPE OF forever committed to returning the fundamental type and saying it's an OBJECT! ?
This hesitance has affected my willingness to rename REB_BLOCK and REB_BLANK to be TYPE_BLOCK and TYPE_BLANK, which would be much more palatable (and survive a language name change away from Rebol...)
There's also the question of type of null, which I feel needs to be an error most of the time. The way I've worked it out so far is that you get a RAISED? error. So if you know you want to test for null you can say try type of null and get a null antiform result--not a datatype, but there's a sort of reasonable logic to saying the type of null is null.
What Would It Hurt, e.g. if SPLICE! Looked Like A Type?
For instance, is there a really good reason why this shouldn't work?
>> to splice! [a b c]
== ~(a b c)~ ; anti
>> to block ~(a b c)~
== [a b c]
switch type of spread [a b c] [
splice! [print "Is this somehow bad?"]
]
It might be confusing, that a type ending in !
can't be put into a block. But that was true before with antiform!...
I lean toward thinking that there's more upside than downside. And I kind of want to put this TYPE vs KIND vs. whatever else issue to rest. We write type of x and expect to get something like BLOCK! or OBJECT! back. If there's something more complex than that, it probably needs to be done another way.
So if you have something like ''''1
and ''''x
and ''''3
, and you want to know which are the "same type", you'll need to define your operators for answering that.
Want to know if they're the same underlying type when you take the quotes off?
(heart of x) = (heart of y)
Want to know if they're at the same quote level?
(quotes of x) = (quotes of y)
I'm sort of tempted to say actually that it might should be that TYPE OF doesn't work on quoted values, because of how misleading it is... but all blocks are of the same type, even if they're different lengths. And it is actually often the case in dialects that if something is quoted, you treat all quoted things the same way...oddly enough.
In any case, the new flexibility for -OF operators means we can get some other ideas in the mix. Rnadomly:
>> quoted-type of first of ['''x]
== &[' ' ' &[word!]]
>> quoted-type of first of ['''1]
== &[' ' ' &[integer!]]
If we say there are more questions you can ask of values to produce structure... instead of putting that burden on TYPE, we can maybe commit to what type does and move along.
And maybe there could be something like class:relax of x which if something wasn't an object, would give you the fundamental type?
>> class of some-novel
== #[make object! ...]
>> class of some-block
** Error: not an object, use CLASS:RELAX to permit other types
>> class of some-block
== &[block]
I guess in other words, I'm feeling like it's time to just go ahead and say that TYPE-OF is the question we build on, that it returns fundamentals or antiform classes.
And maybe the concept I've always wanted of calling it TYPE! instead of DATATYPE! will be possible, too.