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

[REBOL] Re: Bug in 'use? Re:(2)

From: rebol:svendx:dk at: 24-Jul-2000 3:34

Hello Elan, Please see comments below. On 23-Jul-00, [rebol--techscribe--com] wrote:
> Hi Eric, > > you wrote: >> I think it's needlessly complex to say that the g function "has access >> to f-arg". > > That is complex? > >> It's much simpler to say that the word 'f-arg is bound to the >> context of the function F, > > That's "much simpler to say"? ;-). > > Perhaps. It does not say, however, if 'g has access to the f-arg that is > defined in the context of the 'f function. > >> and that the function G has no privileged access >> to that binding of 'f-arg by being within some kind of hierarchy. > > But the embedded function g (a function that is defined in the context of > function f) *does* have privileged access to words local to the context of > function f. That happens to be an empirical fact. The questionable > *simplicity* of saying that function 'g "has no privileged access to that > binding" does not help, since your statement is incorrect. A simple > incorrect statement is not better than a correct one. > > 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. > > The term "f's context table" is simply a shortcut for saying" "all > word/value pairs defined in the context of the 'f function". > > Inheritance means that - without any programmatic efforts - REBOL > automatically exposes f's context table to the g function, because the g > function is embedded in f's context. Even though 'x is defined globally, > the 'x binding effective for 'g is x's binding in 'f, because 'g is defined > in 'f. (Mind you, I am not talking about the set-word g: being defined in > 'f, I am talking about the function itself, the value 'g is associated > with, being defined in 'f. Nor am I talking about 'f. I'm using 'f as a > short way of saying "the function associated with f".) > > This inheritance is hierarchical. Observe: > >>> x: "This is global x." >>> y: "This is global y." >>> z: "This is global z." > >>> f: func [y z] [ > [ g: func [z] [ > [ print ["g's x" x] > [ print ["g's y" y] > [ print ["g's z" z] > [ ] > [ print ["f's x" x] > [ print ["f's y" y] > [ print ["f's z" z] > [ g "z argument passed to g." > [ ] >>> >>> f "The y argument passed to f." "The z argument passed to f." > f's x This is global x. > f's y The y argument passed to f. > f's z The z argument passed to f. > g's x This is global x. > g's y The y argument passed to f. > g's z z argument passed to g. > > Both 'f and 'g inherited the global context table, see the value reported > for 'x. > The 'f function uses the values of its local context table for the words 'y > and 'z. > The 'g function inherits the global context table for 'x, inherits f's > private context table for 'y and uses its own context table for 'z. > > 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.
Please let me interrupt. A few days ago, I'd have said the same thing, but some experiments I've done in the last couple of days (and the thread "REBOL's scoping rules") have convinced me othervice. I agree that some sort of hierarchy exists, but maybe it just "seems to be". I'd like to go thru an example, but to do that, I must make the presumption that each lit-word in REBOL can have it's own private binding (ie. each word can be bound to a specific context). The BIND function can be used to modify a words binding. (I which I could express this better, but well, I can't :-) First the sample script: REBOL [] x: "global x" y: "global y" code-1: [print [x y]] f: func [x] [ code-2: [print [x y]] do code-1 do code-2 g1: func [y] code-1 g2: func [y] code-2 g1 "g-arg-y" g2 "g-arg-y" ] f "f-arg-x" Ok, I'll try to explain what I *belive* goes on during the loading and execution of this script. I'll be using a notation like [x--global], which means: lit-word 'x bound to the global context, and [x--f] means 'x bound to the context of the function f refer to. even though it'd be more correct to write "[print--global]", I'll just write "print" to ease reading. (print, do, func, etc never changes their binding in this example). Immediatly after the script have been loaded, I belive the situation is like this: REBOL [] x: "global x" y: "global y" code-1: [print [[x--global][y--global]]] f: func [[x--global]] [ code-2: [print [[x--global][y--global]]] do [code-1--global] do [code-2--global] g1: func [[y--global]] [code-1--global] g2: func [[y--global]] [code-2--global] [g1--global] "g-arg-y" [g2--global] "g-arg-y" ] [f--global] "f-arg-x" All words are bound to the global context. Now execution begin, x, y and code-1 is assigned values in their present context (the global one). Let's skip to the line "f: func [x] [" A new context is created by "make function!", and the args block is scanned for all lit-words. All lit-words found is then added to the newly created context. (The binding of these words is irrelevant, since they aren't evaluated). In this case the only word created in the new context is 'x. Afterwards, the code-block is recursivly traversed, binding all words in the new context to that context. Here's what the code looks like after this re-binding: (skipping most unchanged lines) ... f: func [[x--global]] [ code-2: [print [[x--f][y--global]]] do [code-1--global] ... code-1 and code-2 are no longer identical, as 'x in the block refered to by code-2 now is bound in context:x (let's just call it that). Nothing more is done (I guess) until f is called by the line 'f "f-arg-x"' I'll skip the two "do code-x" lines for now and skip to the point after the two g-functions has been created: (Also I've manually "reduced" some of the words to their values) REBOL [] x: "global x" y: "global y" code-1: [print [[x--global][y--global]]] f: func [[x--global]] [ code-2: [print [[x--f][y--global]]] do [print [[x--global][y--global]]] do [print [[x--f][y--global]]] g1: func [[y--global]] [print [[x--global][y--g1]]] g2: func [[y--global]] [print [[x--f][y--g2]]] [g1--global] "g-arg-y" [g2--global] "g-arg-y" ] [f--global] "f-arg-x" The output of the script is: ## do %test.r global x global y f-arg-x global y global x g-arg-y f-arg-x g-arg-y The point is, each litteral word always has exactly one context to which they're bound. Nothing more is needed in the above example in order to correctly lookup the value of a given word. This ofcourse adds some overhead at context creation time, because words in deeply nested blocks can end up being bound several times, but given the speedup in word-lookup (one-level) - it's certainly worth it.
>> (The binding of 'f-arg of course took place even before the function G >> was created.) > > Of course. Who was disputing that? I'm describing how g gets to access the > 'f' functions f-arg, not when f-arg is bound to the f' function. Two > different things.
No, it's really the same thing. when function f was created, all occurences of f-arg was bound even in the code-block of g and since g didn't later rebind it, it remained bound to the context of f. (I hope I got it right this time - I've changed my mind over this matter a couple of times :-) -- snip -- Best regards Thomas Jensen