Looking over this, UNSPECIALIZED is a pretty lengthy name.
In a frame, these represent information for parameters that need to be gathered.
Should this be what's called a HOLE? It almost makes the most sense. "A frame with holes in it needs to fill those holes from the callsite."
(Note: It turns out this helps the implementation a lot...because checking for specialization is a particularly narrow function that can only be called on frame variables. Consequently I had the distinction between Is_Unspecialized() to check for the antiform (regardless of where it appears), and Is_Unspecialized_Var() which is constrained to be called on frame variable slots. Having Is_Hole() allows me to drop the _Var() from the commonly called routines.)
I don't like VACANT's part of speech (kind of like how I don't like "UNSET" for what I call NOTHING, because variables are unset, not the values that signify unsetness). But. VACANCY on the other hand...is appropriate.
Hence nothing, hole, and tripwire could all be VACANCY? FRAME!s are concerned in particular about holes. Variable access and defaulting are concerned with vacancy.
A lot of things have jumbled around as I've gotten more experience with this. Notably the idea of making antiform parameters "vacant" in order to let them act as unfulfilled in FRAME! turned out to be a very poor choice in practice.
I've written up how antiform parameters were normalized, and NOTHING is the unspecialized state exclusive to MAKE FRAME!:
What this means is we have an in-memory FRAME! representation for functions, which is what you get back from UNRUN (all it does is remove the antiform state on the FRAME! by changing the quote byte from ANTIFORM_0 to NOQUOTE_1), which gives a plain frame that looks like this:
There might be some shade of distinction...where UNRUN might give you a mutable view of an action, and PARAMETERS OF gives you a read-only view. I don't know.
But you might ask: "Why not have PARAMETERS OF give back a frame with plain PARAMETER! instead of the antiforms, so they're 'easier' to work with?"
That would be more costly and require a separate allocation. The thing is, that what you see there is actually just a Lens of the actual frame that contains non-antiform cells also (specializations and locals), but because of the view it's only showing you the antiform parameters.
But also, a frame with non-antiform PARAMETER! in it isn't useful for building functions.
So really this is holes of append/
Could PARAMETER be the antiform of...something else?
It feels like maybe it should be the case that parameter is the name of the antiform. But the antiform of what exactly?
It isn't really a TYPESET! because there's more information in it (a textual description, whether it's optional or literal, etc.) It could be maybe a TYPESPEC!
This is enough information to gather an argument at a callsite. A GATHER? Maybe a MATCHER?
"parameters are the antiform of matcher!"
The problem is that what's in a PARAMETER! cell is so particular to gathering parameters, and for most practical purposes they're always antiforms.
Or Is There No Real Reason To Use Antiforms Here?
Things have shaken around, and antiform parameters are legal to pass at callsites as non-^META values. The only restriction that you get is that you can't specialize frame slots to antiform parameters (without a bit of effort).
So why not just say that plain PARAMETER! is what represents unspecialized slots?
What led me to resist this initially was that whatever represented unspecialized slots couldn't be passed as a plain argument to functions. This meant if you were going to make some query function for PARAMETER! you had to ^META it, and the meta mechanics are tailored to helping you manage antiforms<->quasiforms<->plain. If PARAMETER! was irregular then it breaks this rhythm, because your meta form is quoted, not quasi...it could be made to work but it would then be rather irregular.
Yet things have changed. You can pass "unspecializeds" normally, you just can't specialize to their value (by definition, since they're a value that represents a lack of specialization). Though I described a workaround through ENCLOSE-based meta mechanics if you ever really need to do this to a parameter that wasn't already defined ^META.
I think being too invested in the isotope story works against practical usage here. If plain PARAMETER! represents unspecialized values in function interfaces, that avoids needing another name for them. You'll have to learn that they are a little weird, but their weirdness is not "you can't put these in blocks" (which there's a good reason for with other types, but never was a particularly good one for parameter antiforms).
It's Really The Best Option
Putting aside whether you know what this code is doing or not:
let f: make frame! make varargs! condition
for-each [key param] (parameters of f) [
all [not param.optional, ~end~ = f.(key)] then [
f.(key): value
break
]
]
vs.
let f: make frame! make varargs! condition
for-each [key hole] (holes of f) [
all [not hole.optional, ~end~ = f.(key)] then [
f.(key): value
break
]
]
vs.
let f: make frame! make varargs! condition
for-each [key unspecialized] (unspecialized of f) [
all [not unspecialized.optional, ~end~ = f.(key)] then [
f.(key): value
break
]
]
It needs to be the PARAMETERS OF, and the variable needs to be called PARAM.
So would dropping antiform PARAMETER! be for the best> Isotopes solve a lot of problems, but once NOTHING moved to the sole unspecialized state in MAKE FRAME! scenarios, having parameter antiforms just seems to be causing mechanical and terminology problems here without adding a lot of benefit...
We'd Lose One Piece Of Terra Firma, Maybe?
If you write a function like:
/specialize-x: func [/action [action?] value] [
let f: copy unrun action/
f.x: value
return runs f
]
That could specialize any function's X value and give you back a function with X fixed. Unless you passed an antiform parameter...which is a stable value (by necessity) and would be legal since you didn't give value a type spec.
But in today's antiform-PARAMETER!-is-unspecialized world, if you said:
/specialize-x: func [/action [action?] element [element?]] [
let f: copy unrun action/
f.x: element
return runs f
]
You'd be able to promise that the specialization would work. There's arguably a non-zero value to say that the set of things you can put in blocks is a subset of all things you can specialize a value in a frame to.
But what about null, or any of the other antiform states that are legal to specialize to? That seems kind of arbitrary.
Really, it may just be that there needs to be a SPECIALIZABLE? (or NOT/PARAMETER?) constraint, and that would address this issue without the "maybe not even that useful" guarantee that array elements can always act as specializations. Who said that specialization-ability and put-in-block-ability had anything to do with each other, anyway?
Not only that, there's nothing stopping there being a richer way of saying 'yes I want to specialize with this PARAMETER! explicitly'.* I've tried to avoid making there be any hidden bits, but SPECIALIZE could offer the feature and implement it however it wanted to. Which doesn't even have to be hidden, it could be METASPECIALIZE and just fulfill all the arguments as one level meta of what was expected.