A major realization about the nature of what ^META-WORD!s should actually be doing has made it fully necessary to rethink things.
Initially I thought that ^foo should be a synonym for (lift get:any $foo). It was a meta-word after all... so the result of evaluating it should produce a meta-state (quasiform or quoted).
...Right...? ![]()
Wrong!
The far more useful concept is to think of it as saying "foo is a variable that utilizes meta-representation". e.g. when something is written to it, then that thing should be lift-on-write.
And then the complement to that should be unlift-on-read.
There was already an inkling of this, with assignments in the SET-BLOCK! implementation:
>> [^foo' bar]: pack [pack [a b] pack [10 20]]
; first in pack of 2 items
== ~['a 'b]~
>> foo'
== ~['a 'b]~
>> bar
== 10
But if you're going to have a "meta-read" operation, the most useful thing is to think of it as "read-meta" and reconstitute the antiform:
>> ^foo'
; first in pack of 2 items
== a
So suddenly ^xxx: becomes a powerful assignment operator, writing the lift of its right-hand side into the variable. Among the great properties it has, is that it pipes the right hand side out to the left as is... so compare:
>> xxx: lift fail "assigning an error"
== <<quasiform error>>
>> ^xxx: fail "assigning an error"
== <<antiform error>>
Hence, you get safety from error assignments! because although it did the assignment of the value lifted, the result is not lifted and you still have to have something sink that error, or it will panic!
We can talk about how lax it should be about decaying packs. Maybe you need a decoration for that, like (^xxx.~: ...) to get them. But I'm leaning to saying it's just your responsibility to say (^xxx: decay ...) if you call a multi-returning function and don't actually want its pack.
Now let's ask about the difference between these things:
obj.^value
^obj.value
^obj.^value
At each step, you have the opportunity to say "this thing is a variable that is meta-represented".
It seems pretty clear this means the meta-mark needs to be inside the slot, not outside on the tuple itself:
>> type of first [^obj.^value]
== ~{tuple!}~ ; anti
>> type of first first [^obj.^value]
== ~{meta-word!}~ ; anti
>> type of second first [^obj.^value]
== ~{meta-word!}~ ; anti