Part of Rebol's design is that every execution frame has an order to its arguments, represented by an integer.
So for instance with IF:
- the CONDITION would be in frame
cell[1]
- the BRANCH would be in frame
cell[2]
NATIVE Functions Use The Ordering
Natives don't have to walk the keys of a frame, e.g. to find a slot that matches the symbol "BRANCH". They are hardcoded to look directly at the index it should be in.
(R3-Alpha hardcoded these indices, and you can see that as D_ARG(1) and D_ARG(2) in the implementation of IF. Ren-C puts the native specs in comments, processed during the build to make macros. These macros like ARG(condition) and ARG(branch) resolve to the integers at compile-time.)
Interpreted FUNC Functions Use Indices Too, But Differently
When a FUNC is being generated, a table is made that maps from symbols for the arguments and locals to the integer for that symbol in the frame.
Then the BLOCK! passed as a body is walked through to find ANY-WORD!s that reference the arguments and locals, and the index is poked into the cells for those words. Then, the binding pointer in the cell is set to point at the function definition.
That isn't enough information to look up the word--because the binding is relative to a function that is not running. Hence it's called relative binding. You need to somehow connect this to an instance of the function that is running and has its argument and local cells filled.
Historical Rebol & Red make this connection dynamically by climbing the stack and looking for an instance of the function seen in the binding. Clearly that doesn't permit indefinite extent (closure) over a local or argument, because when the function isn't running its variables can no longer be found. But it also can be wrong if recursions interact with material bound to various instances of the same function.
Ren-C uses a better mechanism of Specific Binding, where information is slipped through instances of BLOCK!s and other arrays, saying which frame that view of the array is executing on behalf of.
Conflict With New Policy of "Leave Binding Alone"
The bias in the new proposal of binding is that any WORD!s already bound will be left-as is, with only some minor surgery on environments of blocks done by things like FUNC or FOR-EACH, to inject some new variables at the head of the lookup.
That may make it sound like these words which are bound relatively inside function bodies are more trouble than they are worth. In the model, they're actually supposed to be thought of as unbound--so if they carry a secret binding, that could only be used as an optimization when they are actually intentionally combined with the right frame.
The Optimization is Actually Not Minor
Ren-C function frames are unusual, in that a single frame can be reused for several "phases" of a function composition. e.g. you can ADAPT and SPECIALIZE and AUGMENT a function--even a native--and all these just reuse the same frame. But during the phase, it only sees the fields of the frame it is supposed to be able to see.
For instance, if you specialize out the VALUE from append (e.g. by making it always append 5) and then try to ADAPT the resulting function, you won't even know that APPEND has a VALUE at all. It will seem like it only has a series.
Being strict about enforcing this information hiding permits you to do unusual things, like once the VALUE is shielded in the inner function... you can AUGMENT the resulting functions with another argument named VALUE. This process can proceed indefinitely. There could be dozens of fields named VALUE in the frame, but only one visible at a time.
So checking whether a value is visible in the frame is more involved than just walking a list of symbols and comparing them (which isn't necessarily fast in and of itself). The parameter definitions must be consulted also, to see if they line up with the running phase of the function in order to determine the visibility.
The time of function creation is a good moment to do this work, instead of going through it on every lookup. And squeaking performance out of pure virtual binding is going to be hard... we need all the tricks we can get.
Copying The Function Body
R3-Alpha actually had a trick during bootstrap, where while loading the library functions it would use a special version of FUNC that did not copy the function body blocks. It assumed none of them were composed out of parts that were exposed or would change, and if there were exceptions the library authors were supposed to be sophisticated enough to COPY or COPY/DEEP where needed.
(IIRC, it would contaminate these blocks by putting the relative binding information in them, so they would be seen as corrupt if anyone managed to get access to them.)
But after bootstrap was over, it would replace FUNC with a version that deeply copied the bodies.
It invites a lot of accidents in the historical world to have a FUNC that doesn't copy its body deeply. But there are some new possibilities that might be able to avoid accidents while still covering a lot of cases. For instance, it could deeply protect the blocks and make them immutable. This way, if a user ever found themselves bit by it they could add in their own COPY or COPY/DEEP at the relevant places. But 95% or more of the time, you'd not need to and the system could speed up.
In any case, it's interesting that the relative binding information wouldn't be corrupting the binding information any longer, because it's just an optimization for unbound values... and any PICKs or FOR-EACHs would see relatively bound words as unbound.