[REBOL] Bug in 'use? Re:(9)
From: rebol::techscribe::com at: 23-Jul-2000 0:49
Hi Gabriele,
good to hear from you.
> r>> From the point of a statement that is being evaluated, there
> r>> exists a
> r> hierarchy of "Effective Context Tables". The lowest Context
> r> Table in this hierarchy will first be used to search for the
> r> value of a word, and if the word is not found in this context
> r> table, the search will continue in context tables at higher
> r> levels in the context table hierarchy. The lowest table in the
> r> context table hierarchy is the context table that was last
> r> created, "last" in terms of previous statements that were
> r> evaluated.
>
>This was REBOL 1.x behaviour. REBOL 2.x is very different in this
>regard; the word lookup is NOT done at runtime but by the function
>BIND, and there is no context hierarchy.
Yes there is. Three examples:
Example 1 for Context Hierarchy:
global-word: "This is the global word."
f: func [f-arg] [
g: func [g-arg] [
print [g-arg f-arg global-word]
]
g "This is g's argument."
]
In this example we are dealing with three contexts: the global context, in
which global-word is defined, the function f's local context in which f-arg
is defined, and finally, the function g, in whose local context its g-arg
is defined.
The g function inherits f's context table in which f-arg is defined.
Therefore g has access to all three words: It can access global-word,
because global-word is defined in the global context, and g has access to
the global context. It can access g-arg, because g-arg is defined in its
own private context table. The g function also has access to f-arg, which
is defined in f's local context. The g function accesses f-arg in f's
context table, which g inherits.
When I evaluate f with the argument "This is f's argument" I get the
following:
>> f "This is f's argument"
This g's argument. This is f's argument This is the global word.
>>
The g function found g-arg in its own context table, it found f-arg in the
context table of the function in which it was created, f's context table,
which g inherited, and it found global-word in the global context. This
shows that REBOL does support a context hierarchy, when it is dereferencing
("looking up") words.
Example 2 for Context Hierarchy:
f: func [x] [
g: func [y] [
x: y
]
g "this is g's argument."
print x
]
When I run this function I get:
>> f "this is f's argument"
this is g's argument.
Note what is happening here. The g function has its own context table. It
is passed the argument "this is g's argument". It sets x, which is defined
in f's context table, to the string "this is g's argument." Then f prints
the value of x, and that value is the value that was set by g. Context
hierarchies work in both directions, getting and setting words.
Your counter example:
>Anyway, I can prove that there is no context hierarchy:
>
>>> a: 1 b: 1 c: 1
>== 1
>>> obj1: make object! [
>[ a: 2
>[ obj2: make object! [
>[ b: 2
>[ obj3: make object! [
>[ c: 2
>[ ]
>[ ]
>[ ]
>>> blk: [a b c]
>== [a b c]
>>> print blk
>1 1 1
>>> print bind blk in obj1/obj2/obj3 'self
>1 1 2
>
>If contexts where organized hierarchycally the output would have
>been "2 2 2".
is based on the assumption that "embedded" objects are created in the
context of their "parent" objects and inherit the parent object's context.
This is not the case - as your example indeed demonstrates. The set-word
obj2 is indeed defined in obj1's context, but the object it references
(make object! [...]) is not created in obj1's context.
The same thing goes for obj2. The set-word obj3 is created in obj2's
context, but the object it references does not inherit obj2's context.
In other words, the object referenced by obj1 has two context tables, the
global context table, and its local context table. The object referenced by
obj2 again has two context tables, the global context table and its local
context table. It does not inherit obj1's context table. Finally, the
object referenced by obj3 also has access to the global context table and
to its own local context table. It does not inherit obj1's or obj2's
context tables.
In this (and other) respect(s) objects are different from functions.
Whereas objects created in an object (or function) do not inherit the
parent's context table, functions that are embedded in a local context
inherit the context table of the value they are embedded in. A function
inherits the context of an object it is defined in. A function also
inherits the context of a function it is defined in. We saw an example for
an embedded function inheriting a parent's function context. Here is a
mixed example, in which embedded functions inherit a parent object's context.
Example 3 for Context Hierarchy:
a: 1 b: 1 c: 1
context-1: make object! [
a: "this context-1's a."
context-2: func [/local b] [
b: "this context-2's b."
context-3: func [/local c] [
c: "this is context-3's c."
print [a b c]
]
context-3
]
]
>> context-1/context-2
this context-1's a. this context-2's b. this is context-3's c.
In contrast to your example, in this case the statement print [a b c]
evaluated within the context of context-3 (a function, not an object)
reports the values of a b c that were acquired at its own and at higher
levels of the context table hierarchy.
In summary, functions are evaluated in a context hierarchy, objects are
not. Recall that I was discussing the behavior of recursive functions with
Ladislav, not the behavior of objects. My statements regarding context
table hierarchies are correct with respect to functions.
As a side-effect, functions demonstrate that there does exist a context
table hierarchy mechanism in REBOL. You show that this mechanism is not
effective with respect to objects, not that it does not exist altogether! I
show that it exists, and that it is effective with respect to functions.
> r> Multiple "Context Tables" At the time REBOL enters the
> r> function a new "Context Table" becomes effective. This context
> r> table, at this point in time, would like this:
>
> r> word | value
> r> x | 1
> r> y | 2
>
>This is actually created when the function is created, and is
>always effective, even if it is changed every time the function is
>called.
Well, you kind of figured that out by yourself. I demonstrated that the
function's context table is created at the time the function is defined,
before it is evaluated. The context table I show for the function at that
time it is defined, but before it is evaluated is:
word | value
x | unassigned
y | unassigned
The words x and y are arguments of the function. When the function is
evaluated with the arguments 1 and 2, then - and only then - the function's
context table associates the word x with the value 1 and the word y with
the value 2. The context table of the function at the time it is called
with the arguments 1 and 2 - and only then - becomes
word | value
x | 1
y | 2
>You can refer to previous messages in this list by me,
>Ladislav and Brian about the working of function contexts, in
>particular in the case of recursive functions.
I'll check into it. In the meantime, don't be so lazy. Do your insights
differ significantly from mine? If so, in what respect?
Perhaps my mental model of context tables and the context table hierarchy,
multiple context tables that are effective during recursive function calls,
and the stack in which the context tables that are currently defined for a
function are stored, while it is recursively being evaluated, is a good
model to understand recursive function calls?
What do you think?
> r> If REBOL created a private context table for the function at
> r> the time the function was defined, then it will not be able to
> r> retrieve a value for x, because the function was not evaluated
> r> yet, and no value was assigned to x as yet.
>
>Ah, ok, so did know this already. :-)
>
> r> word | value
> r> x | unassigned
>
>Actually is:
>
> word | value
> x | unset!
My notation intends to report that no value was assigned to 'x. Feel free
to use unset! where I use "unassigned".
> r> What we should note here is that apparently REBOL remembered
> r> all three context tables for the function f, even while it was
> r> in the third (recursive) function call to f. In other words
> r> the f function was temporarily associated with three context
> r> tables. At the deepest recursion-level the two context tables
> r> it acquired during the previous calls to f were remembered.
>
>Ladislav suggested that only tha values are remembered, while the
>context table is reused. So the function has still only one
>context table in any time, but keeps a stack of values.
Gabriele, it's obvious that more things are being remembered than just
values!
1. The association of words with values is being remembered!
2. The fact that the association of these words with these values is
effective for this particular function is being remembered.
1 and 2 together is by my definition a private context table for the
function. I was not proposing that REBOL has some internal structure called
a context table.
I was only using the term "context table" as a means of describing REBOL's
behavior. Whatever it is that REBOL implements, it looks, walks, smells and
talks like a context table.
I introduced the idea of a "context table" to express a function's
currently effective, or active, bindings of words with values. Now you tell
me that, no, not the context table, BUT the association of words with
values is remembered? These are not two things. The association of words
with values is what I defined as a context table. So if the association of
words with values is indeed being remembered, then the context table, which
is just a mental model, a shortcut to say association of words with values,
then the context table is being remembered because "context table" is just
another way of saying the word/value pairs are being remembered.
3. The context tables (or word/value pairs) that were effective for a
function during a previous evaluation of the function are remembered during
recursive function calls.
As a function steps out of lower-level recursive function call back into
the recursion level from which it was called, the context table that was
associated with the function at the time the called itself recursively,
once again becomes the currently effective context table for this function.
I proposed the model of stack of context tables, to describe REBOL's
behavior with respect re-activating context tables when it returns to
previous recursion levels.
> r> Then we 'a associated with the current-recursion level, and
> r> subsequently called f recursively. If f continued to use its
> r> previous context table, then, while x was set to a lower level
> r> by virtue of the function call f (x - 1), a was not modified
> r> yet, so 'a should continue to be associated with 1, the value
> r> of recursion-level, during the privous call.
>
>I think this does not prove that a new context table is created.
>Creating a new context table would require a new binding of the
>function body.
In my model a function is bound to a context. The context is described by a
context table. The function's binding to the context is not impacted, when
the table describing the context is changed.
>Only the value column is stored in a stack and
>reinitialized, as happens when the function is called the first
>time.
Ths is an implementation issue and does not touch on the descriptive
quality of the theoretical model. Is anything gained with respect to
discussing a behavior model of recursive function calls by arguing about
how that model is implemented?
I think the question should be, does the model allow you to correctly
predict the behavior of recursive function calls? Does it do so with a
minimum of theoretical constructs? Is the model simple to understand?
Take Care,
;- Elan [ : - ) ]