[REBOL] Re: ... Scope yet again...
From: lmecir::mbox::vol::cz at: 11-May-2001 23:15
Hi,
Joel wrote:
> ...fascinating, especially in view of the behavior
> of
>
> >> ff: func [arg cond /local locvar] [
> [ use [usevar]
> [ locvar: arg + 1
> [ usevar: arg + 2
> [ print ["in :" arg cond locvar usevar]
> [ if cond [ff arg + 10 false]
> [ print ["out:" arg cond locvar usevar]
> [ ]
> [ ]
> >> ff 1 true
> in : 1 true 2 3
> in : 11 false 12 13
> out: 11 false 12 13
> out: 1 true 2 13
>
> One might infer from your example that encountering USE causes an
> "unnamed context" to be created and that leaving the body of the
> USE causes that context to become inaccessible except via any
> persistent exported references -- every pass through the loop
> gets a "fresh" X instead of using the one from the previously
> existing USE context.
>
> However, the behavior of FF implies that the recursive invocation
> of FF did *not* get a fresh USEVAR, but instead somehow had access
> to the one in the context previously created.
Not at all, that is only a Use bug. Use really creates a new context every
time it is invocated (a fresh 'usevar word everytime Use is invocated). The
only problem with Use is, that it modifies its second argument (the Body
block) when it binds it to the newly created context. This is the source of
the problem in the Ff function above, where the Print function doesn't have
access to the correct 'usevar word, because the word gets modified by the
subsequent call to Use.
To be more concise, the body of the Ff function is Self Modifying. To repair
the code you can replace Use by its non-modifying counterpart:
nm-use: func [
{
A non-modifying use version.
Defines words local to a block.
}
[throw]
words [block! word!] {Local word(s) to the block}
body [block!] {Block to evaluate}
] [
use words copy/deep body
]
After the replacement, the Ff function will no more be Self Modifying and it
will work fine.
Another interesting example:
b: copy []
rep: func [n] [if n <= 3 [append b 'n rep n + 1]]
rep 1
b ;== [n n n]
reduce b ;== [1 1 1]
If we use E-func instead of Func as below, we get:
b: copy []
rep: e-func [n] [if n <= 3 [append b 'n rep n + 1]]
rep 1
b ;== [n n n]
reduce b ;== [1 2 3]
E-func is a "repaired" Func and you can find it in
http://www.sweb.cz/LMecir/highfun.r
> So... did that "context previously created" come into existence
> when the upper/outer invocation of FF occurred, or during the
> execution of FUNC when the body of FF was created, or ... ?
>
The new context is created every time Use is evaluated, but Use modifies the
Body block, which is a source of trouble (an invisible Self Modifying Code).
Regards
Ladislav
P.S. I would like to suggest everyone, who is interested, and didn't read
http://www.sweb.cz/LMecir/contexts.html
, or http://www.sweb.cz/LMecir/rep.html to have a look at these.