That is the intended meaning. var x: 1 is only variadic as an implementation detail of how it manages to pass its "variable declaration" on to influence the stream of code that comes after it.
But...can a "virtual" approach actually work?
Bindings Need to be Preserved
Rebol constantly passes blocks of symbolic code from one routine to another routine to execute or inspect. Even though the implementation of the called routine may have some local variables expressed symbolically with the same name--there can't be interference.
do-code: func [code <local> x] [
x: 2 | do compose [-- "DO-CODE's x is" (x) | (code)]
]
my-print: func [arg <local> x] [
x: arg | do-code [-- "MY-PRINT's x is" x]
]
If you call my-print 1, you will get:
-- "DO-CODE's x is" x: 2
-- "MY-PRINT's x is" x: 1
This is foundational. It has to be the case that inside the body of DO-CODE, both x's preserve their intended binding--so long as DO-CODE doesn't "mess with x" inside a block that defines x.
Can a naive VAR implementation do that?
Let's try the same thing using VAR instead of :
do-code: func [code] [ // now no `<local> x`
var x: 20 | do compose [-- "DO-CODE's x is" (x) | (code)]
]
my-print: func [arg] [ // also no `<local> x`
var x: arg | do-code [-- "MY-PRINT's x is" x]
]
An inefficient implementation of VAR could build a block out of everything that came after it, bind it, and DO it. That would work because there'd be a clear moment in time where it ran. It would essentially do the same thing as USE, so it would do this transformation:
var x: arg | do-code [-- "MY-PRINT's x is" x]
=> use [x] [x: arg | do-code [-- "MY-PRINT''s x is" x]
var x: 20 | do compose [-- "DO-CODE's x is" (x) | (code)]
=> use [x] [x: 20 | do compose [-- "DO-CODE's x is" (x) | (code)]
In today's world, that's quite a lot slower than using a fixed binding to a local. The USE has to deep copy and rebind the block, create a new separate context, bind the Xs into it, etc.
But yes, it works. Outside of being slower, you wouldn't know a difference from an explicit <local>
or gathered one... except that the X would only apply from where its VAR was declared up to the end of the block or group it's in. And this is actually a fairly desirable property; if you want it to apply more widely, you apply it at a more outer scope.
But could a savvier VAR work efficiently?
Let's imagine a VAR that doesn't actually bind anything in-the-moment. Instead it puts a little bit of "magic" onto the executing frame, via the suggested trick of binding a VARARGS! feed. This would end up gluing the magic onto values as the frame went along in processing its current level.
I've used ~1
and backslashes to denote the augmentation of the ensuing values:
var x: arg | do-code [-- "MY-PRINT's x is" x]
=> ~1\do-code\ ~1\[-- "MY-PRINT''s x is" x]\
So now, when DO-CODE is passed the BLOCK!, that block has some extra baggage. Its own body has a VAR, that puts its magic on too. We'll denote that with ~2
:
var x: 2 | do compose [-- "DO-CODE's x is" (x) | (code)]
=> ~2\do\ ~2\compose\ ~2\[-- "DO-CODE's x is" (x) | (code)]\
This magic is supposed to be a no-op on anything it doesn't apply to, so ~1\do-code\
just runs DO-CODE with its existing binding, same for the DO and COMPOSE.
So our interesting question is what happens when the "magic" conflicts. Whatever ~
means, it can't mean "override any binding of anything under me named x". This would risk ~2
beaming its influence down into the composed code and overriding the ~1
that is intended to guarantee MY-PRINT's x is 1
.
I don't offhand have the answer to this...
...and don't have time to wrestle it today. But this is the phrasing of the problem, and it resembles other problems that mechanics have been created to solve (definitional returns and derived binding both use variations of this "magic".)
I'm getting the feeling that if there were a good solution to it, that it could well be a better answer to how to deal with locals than the "locals-gathering" that FUNCTION does. While being able to do such gathering may make sense for some constructs--and Rebol should certainly be able to do it--it has a number of huge downsides when it collects things it shouldn't. It would be a real victory to get down to just one type of FUNCTION...with a working VAR...that's still in line with Rebol's model and permits the cool feats.