"MORE Time Has Passed, And I Haven't Had Any Better Ideas". Pushing forward with isotopes made an already bad situation with the 64-bit TYPESET! worse. Isotopes bring in a new isotopic form of every datatype, necessitating things like splice!, activation!, and matcher!. But my verdict is that isotopes (and the reimagining of void) are the undeniable direction of solution to classic problems with the language...so...
I have implemented the strategy, and it is limping along...actually running.
New Types: &word, &tu.p.le, &pa/th, &[...], &(...)
I decided to take the ampersand to make TYPE-WORD!, TYPE-BLOCK!, TYPE-GROUP!, etc.
A basis of this replacement for typesets is that &(...) are "type AND groups" and &[...] are "type OR groups".
Spec blocks convert regular blocks to these implicitly, and you can combine them there without the ampersand:
foo: func [arg [(integer! negative?) block!]] [
... you know arg is either a negative integer or a block ...
]
If the argument wouldn't pass the type checking of a function referenced in one of the type containers, then that counts the same as a failure. Hence NEGATIVE? would imply a test for DECIMAL! or INTEGER!.
Exempting ANY-VALUE? from taking ANY-VALUE!
In order to solve the recursive nature of this, the ANY-VALUE? function has no type on its argument...which means don't type check it. Hence ANY-VALUE! can indeed be expressed as &(any-value?) without causing an infinite loop.
Of course, opening typechecking to arbitrary computation does introduce a lot of potential for problems...including but not limited to infinite loops. But we can get infinite loops a lot of ways.
Speeding Up Checks for Common Types
When you express something like the type constraint for ANY-SERIES! as &(any-series?) that might make it seem that each call to a function like APPEND would always be calling a type checking function--possibly several. This seems to add significant overhead.
But I added an optimization. The type checking machinery can make exceptions for these built-in cases and just skip the function call...doing a fast test based on something like the historical bitset-based typesets...so long as ANY-SERIES? points to the definition it thinks it does.
LOGIC! is a type constraint
With this, we see LOGIC! ceases to be a foundational type, but a type constraint...it's actually an isotopic word which passes the test for logic by being either isotopic ~false~ or ~true~:
logic!: &(logic?)
And this ushers in a new era of thinking about the usage of types. It means moving away from:
switch type of x [ ; old way
logic! [...] ; would never happen, since TYPE OF TRUE is &isotope
block! [...]
]
So this should be replaced with something new where the type constraint function or matching is called. We're running out of words, so I propose a refinement as switch/type
switch/type x [
logic! [...]
block! [...]
]
The question of what concrete type something is will matter in a few cases, but we'll just have a limited number of concrete types, which will include &isotope and "ed. So you won't be able to say type of and get back a logic! (for instance)
Hence, TYPESET! No Longer Exists
This solves the typeset representation problem because they just don't exist anymore. They are functions, some of which are native and can be recognized and tested for without going through function calling machinery.
You need to use MATCH functions with them. Because if you try to FIND on what you think of as a typeset, you will just be interacting with it as a block or group...nothing special.
>> positive-integer!
== &(integer! positive?)
>> find positive-integer! 'positive?
== &(positive?)
So instead, use match function is how to do type tests... not FIND.
>> match positive-integer! 10
== 10
>> match positive-integer! -10
== ~null~ ; isotope
>> match positive-integer! "hello"
== ~null~ ; isotope
Amazingly I Have This Working, But It's Far From Good
The code is a wreck, held together only by the fact that it's got so many asserts in it that I can make it limp along. It will take time to hammer it into shape good enough to push out.