[EMAIL PROTECTED] wrote:
>
> Hi Ladislav,
>
> you wrote:
...
> >
> >Let's get to the above example, but let's use a little bit different code:
> >
> >f: func [/local a b] [ a: "" b: copy "" for i 1 6 1 [append a i append b i]
> >print a print b]
> >>> f
> >123456
> >123456
> >>> f
> >123456123456
> >123456
> >>> f
> >123456123456123456
> >123456
> >
...
>
> then we would be very surprised by the following demonstration,
> wouldn't we?
>
> f: func [/local a b] [
> a: ""
> b: copy ""
> for i 1 6 1 [
> append a i append b i
> ]
> print a print b
> insert pick second :f 5 copy/part second second :f 6
> ]
>
> The line in which 'b was created wasn't changed. Most dramatically, it
> continues to be the exact same line you commented on as
>
> >the creation of B
> >is "dynamic" as opposed to A, where the creation is "static"
>
...
> Let me see an explanation that maintains that
>
> >the notions of "global" vs. "local" are misleading in this case.
>
> as you claim, while it manages to explain away the fact that while
> a and b continue to be created in the exact same way the were before...
>
OK. I'll have a go at it.
1) At translation time the text which begins with (sans formatting)
[a: "" b: copy "" ;...etc...
is translated into a block. The second element of that block is
initialized to refer to the empty string, as is the fifth element
of that block.
2) When the entire expression has been translated, it is immediately
evaluated (since it was typed into the REBOL console). Doing so
defines a word 'f in the global context. The value associated
with 'f is an entity of type 'function! whose second element is
a deep copy of the block discussed in 1). For brevity, I'll
refer to the second element of the 'function! value associated
with 'f as #BARNEY# (I'm speaking "commentary" here, not REBOL).
3) When 'f is invoked, a local context is created for the words 'a
and 'b, then #BARNEY# is evaluated. This evaluation causes the
following events to occur:
3.1) 'a is set to refer to the second element of #BARNEY#.
3.2) 'b is set to refer to a copy of the fifth word of #BARNEY#.
3.3) 'a is passed to 'append, which modifies the data of the
string to which 'a refers. Since 'a refers to the same
string as the second word of #BARNEY#, this has the side-
effect of modifying the data referred to by the second word
of #BARNEY#.
3.4) 'b is passed to 'append, which modifies the data of the
string to which 'b refers. Since no other references to
that string exist (it was created only in step 3.2), the
side-effect of this modification is limited to 'b.
3.5) The values to which 'a and 'b refer are displayed on the
console.
3.6) The fifth element of #BARNEY# is modified by inserting a
copy of the second element of #BARNEY#.
4) Upon completion of the evaluation of 'f, the local context
created at the beginning of step 3 is destroyed. With no
"surviving" references to it, the value associated with 'b is
now subject to garbage collection.
5) As long as 'f remains associated with the same entity of type
'function! and the value of #BARNEY# remains unchanged (except
via step 3.6 above), there will remain a chain of references
from the global environment to the second and fifth elements
of #BARNEY#. Therefore, their values (and changes thereto)
will persist between invocations of 'f.
"Aha!", one might say, "The words 'global' and 'local' are all thru
that description!" And so they are. But most of those occurrences
are irrelevant to the point at hand. The real driving factor for
this entire discussion has been the question of why an evaluation
that sets a word's value based on a literal string can produce
different results on repeated use. That phenomenon occurs regardless
of whether the word in question is global or not. It doesn't even
require a function! For example:
>> trick: [a: "" append a "X"]
== [a: "" append a "X"]
>> do trick
== "X"
>> do trick
== "XX"
>> do trick
== "XXX"
>> trick
== [a: "XXX" append a "X"]
Which can be made "non-accumulative" by:
>> trick2: [a: copy "" append a "X"]
== [a: copy "" append a "X"]
>> do trick2
== "X"
>> do trick2
== "X"
>> do trick2
== "X"
>> trick2
== [a: copy "" append a "X"]
The accumulation stops because 'trick2 uses 'copy to create a fresh
string each time, and the modification is not made with a reference
to a persistent string.
The subtle point over which so many of us have tripped (judging by
the discussions on the mailing list) is that the the adjacent
quotation marks in the text entered to define 'trick serve simply
as the INITIAL VALUE of the second element of 'trick, and that
subsequent modifications (via any reference) to that second element
will persist as long as 'trick does. That is the only point where
the concept of "global" appears, as far as I can tell. Values are
not subject to garbage collection as long as there is any reference
(or chain of references) to them from the global context. "Local"
doesn't enter into it at all.
The fact that one can defeat the attempt to generate a fresh string
by using self-modifying code doesn't change the fact that, when one
is allowed to do so, using a fresh string for each invocation is a
viable way around persistence.
-jn-