Key Question on Virtual Binding and Mutability

On this topic...two years later... (!)

By definition, a virtual bind does not change the bindings in the thing it is operating on. It just provides a new "view" of it.

>> obj: make object! [x: 10]
>> block: [x + 1]
>> bind block obj
>> do block
== 11

>> do use [x] compose/only [x: 20 (block)]
== 21

>> do block
== 11  ; Rebol2 and R3-Alpha say 21

Structural Changes To The Underlying Block Are Reflected

If you virtually bind something (e.g. with IN) then you will see changes made to the original array:

>> obj: make object! [x: 10]
>> block: [x + 1]
>> bind block obj
>> do block
== 11

>> obj2: make object! [x: 20]
>> virt: in obj2 block
>> do virt
== 21

>> append block [+ 300]
== [x + 1 + 300]

>> do block
== 311

>> do virt
== 321

BIND-based Changes Are NOT Reflected In The Virtual View

The virtual view's job is to override the stored binding in the shared block. So if you change the bindings of any overridden words, those will not be reflected in the view:

>> obj3: make object! [x: 30]
>> bind block obj3

>> do block
== 331

>> do virt
== 321

That could be pretty confusing if you run a BIND operation on something virtual and find that it's being ignored...

>> virt
== [x + 1 + 300]

>> bind virt obj3  ; where x is defined as 30
>> do virt
== 321  ; the x was unaffected

This Suggests CONST By Default for Virtual Views?

Virtual binds are designed for assuming you're not the only one interested in the block. Destructive BIND is for blocks you yourself LOAD or COPY, and can control.

Being CONST wouldn't stop you from doing binding...it would just make you say MUTABLE on the argument first. The const would give you a hint that things might not behave how you wanted.

And having the virtual views be const doesn't mean the original block is immutable. You can still change the binding there, and you will see changes. (Any changes that aren't part of the virtual bind will also be reflected.)

It seems like a good conservative place to start.

1 Like