Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search

[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 [ : - ) ]