[REBOL] Bug in 'use? Re:
From: kgd03011:nifty:ne:jp at: 24-Jul-2000 12:44
Hi Elan,
I think you're going to be really busy refuting Ladislav, so I'll keep
my comments brief.
You wrote:
>Observe:
>
>>> x: "This is global x."
>
>>> f: func [x] [
>[ g: func [] [
>[ print x
>[ ]
>[ ]
>
>>> f "this is f's argument x"
>
>>> h: func [] [ print x ]
>
>>> h
>This is global x.
>
>>> g
>this is f's argument x
>
>Why does the function associated with 'g (I'll call it the 'g function)
>report f's argument, and not the global 'x, as 'h does?
>
>It's because the 'g function, which is defined in f's context, inherits f's
>context table. Therefore the 'x it prints is the 'x bound in f's context,
>not the global context.
Your explanation agrees with your example, but I don't think it's quite
the best one. I think the best explanation (which I'm mostly basing on
what Gabriele and others have said) is:
Before the function G is constructed, its body block, [print x] is
already bound to the context of the function F. Of the two words in this
block, 'x is defined in the "context table" of F. So when G is
constructed, this block is bound to G's context, but since 'x is not
redefined in that context it simply retains its binding. You could say
that G inherits the binding of 'x, but I don't see any proof that G
inherits f's context table
.
I think your explanation about embedded functions inheriting context
tables has the potential of causing major confusion. My previous example
was a lousy one, but here's an example involving embedded functions that
can easily occur:
>> b: [print x + y]
== [print x + y]
>> f: func[x][g: func[y] b print x]
>> x: 100
== 100
>> f 10
10
>> g 1
101
If you think in terms of "inheriting context tables", wouldn't you expect
G to print 11? That's certainly what I would think.
What happens here accords with my explanation, though. When G is
constructed, in its body block 'x hasn't been bound to the context of F,
and that binding doesn't change - it's still bound to the global context.
This happens because the body block wasn't actually in the block that
was bound to F's context - only the word 'b referring to the body block
was. (Actually, the bindings in the original B are unchanged, since a copy
is used to construct G.)
>I think this inheritance behavior is expressed fairly well with the word
>"hierarchical inheritance". There is a hierarchy of context tables. REBOL
>constructs this hierarchy top-to-bottom, from the higher-level function
>down to the lower-level function defined in the higher-level function's
>context. REBOL consults with context tables in the hierarchy bottom-up when
>it resolves words and looks up what the value they are bound to, beginning
>with the context table for the lower-level function, and, if it can't find
>the word's definition there, it searches in the next-higher context table,
>and so on, until it arrives at the global context table.
When is it that "REBOL consults with context tables"? At run time? When the
function is constructed? Surely it's the latter.
I think a simpler explanation than hierarchical inheritance is that
when a function is constructed, it simply binds all the words in its
body block that are defined in its own context (that is, its own arguments
and local variables), and retains the binding of all other words. If one of
the words in its body block happens to be bound to the context of another
function, that word will retain its binding, whether or not one function is
embedded in another one.
Ladislav's tools for examining binding are very interesting. I'd just
like to extract and adapt the crucial part of his argument that proves
that contexts are not inherited:
>> x: y: z: 0
== 0
>> f: func[x z][g: func[y] [print [x y z]]]
>> f 10 30
>> g 20
10 20 30
>> b: reduce [
[ bind 'x probe second second second :g
[ bind 'x probe third second second :g]
y
z
== [x x]
>> reduce b
== [0 10]
This shows that the word 'x is nowhere in G's context table. The word 'y
which _is_ in G's context does not allow us to access any bindings for
'x except the global one. The word 'z which is in F's context table _does_
allow us to access F's binding for 'x.
Wish I'd thought of that!
See you,
Eric