What Dialects Need From Binding

All you can do with a function is call it. So you've accomplished the hole punching, but at the cost of becoming a black box.

(I wrote the post showing COLLECT and KEEP's implementation to point out that we did already have instances where LAMBDA was used to do the binding work. For that case it works...though it may not be the most efficient way to go about it. But other cases might not be able to use the approach.)

If you're assembling a block with the goal of passing it to a dialect, then such black boxes undermine its ability to interpret that block under the meanings it wants.

A block which has been assembled/composed together where some slots were UNUSE'd via a binding instruction (that IN can coalesce) can still be enumerated and treated as a dialect... with contents inspected literally to implement a mini language, while DO-ing and GET-ing some parts of the structue.


Beyond not being a fit for when blocks are the desired currency, functions also bring in performance implications. They've historically made a deep copy of their bodies. If they did not:

>> block: [print "Hello"]

>> foo: func [] block

>> append block [print "World"]

>> bar: func [] block

>> foo
Hello World

>> bar
Hello World

That copy has an associated cost. We could say "that's not a bug, it's a feature" and that it's the responsibility of the user to make their own copies in this situation. Or perhaps the block just becomes deep locked on function creation, to force you to make copies if you want to modify. (Copying has historically served a dual purpose of allowing the copied body to cache the binding relationship of deep-walked words for arguments and locals to the function, but that may be unnecessary/impossible in the pure virtual binding model.)

Even so, implementing UNUSE via a function would add expense, as it needs to build the function and then build a frame to invoke. A binding instruction that IN understands as part of the specifier chain would presumably be a lot more efficient.