With the arrival of ALIAS, it's one of the first actually deployed "bedrock states"... with all of the questions and issues that they bring up:
https://rebol.metaeducation.com/t/the-return-of-alias/2129
You Can't Detect A Bedrock State By GET-ing A Variable
So for example: once you set up a variable as an alias, if you're just using normal functions, there's no way you can tell it's an alias.
Let's write an unstable antiform pack into an alias:
>> x: 10
>> y: alias $x
>> ^y: pack [1 2]
== \~['1 '2]~\ ; antiform (pack!)
>> ^x
== \~['1 '2]~\ ; antiform (pack!)
You used ^META access...the "lowest-level" way to evaluate, and you saw an unstable antiform.
But that's the end of the line. Reading can't "see" the bedrock state. You have to use some kind of special access function, something like get-alias $y, to find out.
Assignments with SET-ing Are A Different Story...
At first I thought you wouldn't be able to write a bedrock state to a variable through normal evaluation, either.
But I realized there was a loophole.
The loophole comes from noticing that historically, PACK! only uses lifted states for its contents:
>> pack [1020, null, quote 304]
== \~('1020 ~null~ ''304)~\ ; antiform (pack!)
- If you started with an antiform, you got a quasiform
- If you started with a plain value, you got a quoted
- If you started with a quoted value, it got another quote level
But you'd never see PACK! with--say--a plain WORD!, or RUNE!, or BLOCK!, or FRAME!, or INTEGER!...
Those packs would be considered "undecayable", and were errors.
There are exactly as many of these states as the number of states that bedrock cells can have.
So if instead of saying that decaying them is necessarily an error, we could say that if you assign such a PACK! to a plain variable, that means "assign as bedrock". I've done that with alias, where it uses META-WORD and META-TUPLE as the aliasing forms.
I've been calling such packs "undecayed bedrock"...
>> alias $x
== \~(^x)~\ ; antiform (pack!) "bedrock: alias"
So that is an undecayed alias.
You'd get such values back from an UNDECAY function:
>> x 10
>> y: alias $x
>> get $y
== 10
>> undecay $y
== \~(^x)~\ ; antiform (pack!) "bedrock: alias"
Obviously it can't bring back values that are no longer there:
>> z: pack [10 20]
>> undecay $z
== 10
So it only really "undecays" bedrock.
This Is Spooky... Spookier Than Ghosts! 
It seems a little bit scary, that the return result of an arbitrary function could be something that when you assign it, gives mysterious properties.
So I don't think arbitrary functions should just cascade these things around.
Hence I'm skeptical that things like this should work, at least not out of the box:
my-alias: lambda [var] [alias var]
It's a little hard to say that the reason that it wouldn't be allowed would be because of typechecking. I can't really see the concept of carving out these weird antiform GROUP!s and saying "that's not a PACK!"... or.... "that's not an ANY-VALUE?".
And they should probably have to obey the general laws of lifting and unlifting, so that you can pipe the states around. UPARSE depends on it, for things like the GROUP! combinator to be able to pipe things to the SET-WORD! combinator.
e.g. this seems it should be possible:
>> parse [a a a b b b] [let x: some 'a, let y: (alias $x), y: some 'b]
== b
>> x
== b
So I kind of imagine there'd be some kind of bedrockable marker you could use to mark functions as capable of producing undecayed states (similar to "vanishable" for making ghosts disappear).
What Should The States Be?
I picked ~(^foo)~ and ~(^foo.bar)~ for the aliases because it didn't seem to make sense to take the prized "word! space".
In fact, the word! space could give us something very interesting... clean-looking undecayable values. They'd be like cheap variations of the unstable ERROR! antiform.
>> var: ~(hot-potato)~
** PANIC: Undecayable PACK! ~(hot-potato)~
It's a little bit unfortunate that these look similar to SPLICE ~[cold-potato]~. And perhaps a bit unfortunate that for quite a long while up to this past week, splices were GROUP! antiforms (I still have lots of posts here to correct, as I see them)
However, if you're going to say "people can't tell the difference between ~(...)~ and ~[...]~" they probably have a bigger problem in the language, as (...) and [...] are also different. ![]()
But I've wanted something like this, e.g. to denote unreachable code.
switch type of data [
integer! [...]
block! [...]
~(unreachable)~
]
That's slick. I think that if you were forced to use a more decorated type, like ~(#unreachable)~ it would lose its luster. But if you weren't forced you could still chose word spellings that stood out more for your purposes:
switch type of data [
integer! [...]
block! [...]
~(=bad=)~
]
switch type of data [
integer! [...]
block! [...]
~(--fail--)~
]
switch type of data [
integer! [...]
block! [...]
~(DEAD_END)~
]
I actually kind of do want to call it a hot potato, it's kind of rounded.
>> ~(unreachable)~
== \~(unreachable)~\ ; antiform (pack!) "bedrock: hot potato"
Should "Blackhole" Be A WORD!, or BLANK, COMMA!?
When you say:
for-each [x _ z] [1 2 3 4 5 6] [...]
There is actually a slot created for that middle blank in the object made to represent the iteration. Otherwise it would be difficult to encode the notion of "skipping"...the easiest way is just to make a slot, and have writes to it be a no-op.
It used to be the variables were written to but just never observed. They stored the state. But that meant they kept things GC live (and could do so indefinitely, if the iteration object had references leak).
So with bedrock states I thought this should be a blackhole. I wondered if that should be the word ~(blackhole)~ or something like ~(_)~ ... but pursuant to what I say above, words should be reserved for the bedrock states that you can never assign.
It might seem that ~(,)~ with a COMMA! would be a better choice than space, because it's a unit type...so it wouldn't be implying a meaning for all the other potential ~(#rune)~ bedrocks. But this may be useful for something else. I've spoken before about a "true unset" though exactly how this applies I don't know.. but if it existed, it would probably need to be the COMMA! dual.
So space may be the best choice here.
Do All Setters/Getters/Accessors Store FRAME! ?
If you're going to write a single "accessor" function that acts as a setter -or- a getter, then you either need a refinement to tell you which operation you're doing, or the argument has to be lifted.
If the single argument is lifted and it's null (or void, or whatever), then you can know that means GET. Otherwise you want to set to the unlifted value.
While that works, it's a bit burdensome. If I were writing a GETTER, I'd want a light notation like:
>> obj: make object! [foo: 1020, bar: getter does [foo + 304]]
== &[object! [
foo: 1020
bar: 1324 ; getter
]]
>> obj.foo: -4
>> obj
== &[object! [
foo: -4 ; getter
bar: 300
]]
(I'm assuming that getter [...] with just a BLOCK! could act like getter does [...])
I guess it could detect the arity of the FRAME!, and if it's arity-1 assume you're prepared to take the argument as lifted.
But that's a bit unfortunate for a SETTER, which only knows setting... so why should it have to deal with lifting?
Then there's also the question of caching a last value from the getter, so that it's not called every time you get a printout in the console. The semantics get a bit weird.
Anyway Just Wanted To Get Some of That Down
I think I talked myself into the idea of all plain WORD! in the dual band as being reserved for undecayable hot potatoes.
So that means I'm not considering things like ~(blackhole)~ instead of ~(_)~, which is one thing I was contemplating...!
