[REBOL] Re: bug?
From: joel::neely::fedex::com at: 20-Sep-2001 2:07
Hi, Hallvard,
You've stumbled upon the Great Literal Misconception, which
most serious programmers encounter in their REBOL career! ;-)
The key is that literal values don't behave as you think
they do, if you're used to using them in other languages.
Hallvard Ystad wrote:
> How is this possible:
> >> source dummy
> dummy: func [][
> return-value: "1"
> append return-value "1"
> return-value
> ]
> >> print dummy
> 11
> >> print dummy
> 111
> >> print dummy
> 1111
> >> print dummy
> 11111
> >> print dummy
> 111111
> >>
>
> Why doesn't dummy yield "11" all the time?
>
Taking a simpler case (to focus on the "literal" issue
apart from the behavior of functions), we have
>> foo: [val: "1" append val "1" val]
== [val: "1" append val "1" val]
>> foo
== [val: "1" append val "1" val]
>> do foo
== "11"
The result is as expected, but now look at FOO ...
>> foo
== [val: "11" append val "1" val]
... which keeps on happening.
>> do foo
== "111"
>> foo
== [val: "111" append val "1" val]
Here's a clue, if you're the type who wants to figure out
things by yourself.
>> foreach item foo [print [(type? :item) "^-" (:item)]]
set-word val
string 111
word append
word val
string 1
word val
Here's the key: in most programming languages, the appearance
of a statement corresponding to
val: "1"
means that a new string containing "1" is created and the
variable (in other languages, remember) is set to refer to
that new string. In REBOL, this behavior requires that you
explicitly say
val: copy "1"
So what's happening without the COPY? Everytime that FOO is
DOne, the word VAL is set to refer to the STRING! value at
FOO/2 (not a copy, but that string itself!). Since APPEND
modifies the value of its argument, the second element of FOO
is modified by each evaluation of FOO.
Remember that REBOL does not distinguish between blocks that
contain data
and blocks that "contain code" because all
REBOL blocks really just contain values! (Some of which do
interesting things when the block is DOne or REDUCEd ...)
Therefore the content of a REBOL block is capable of being
modified during evaluation. The fact that the second element
of FOO was *initialized* by a literal in the original source
text is no longer relevant.
>> foo: reduce [
to-set-word "val" to-string 3 - 2
to-word "append" to-word "val" to-string #"0" + 1
to-word "val"]
== [val: "1" append val "1" val]
>> do foo
== "11"
>> foo
== [val: "11" append val "1" val]
Another way to see a similar modifying effect is to consider
the use of two blocks, as follows:
>> tweedledee: ["1"]
== ["1"]
>> tweedledum: [val: tweedledee/1 append val "1" val]
== [val: tweedledee/1 append val "1" val]
>> do tweedledum
== "11"
>> tweedledee
== ["11"]
>> tweedledum
== [val: tweedledee/1 append val "1" val]
Notice that the value to which VAL is set (in this case, the
first and only value in TWEEDLEDEE) is modified by evaluating
TWEEDLEDUM, even though it was initialized from a quoted string
in the source text. This behavior (modifying the referenced
string value) is consistent, regardless of where the string
happens to be located or how it was initialized.
HTH!
-jn-
--
------------------------------------------------------------
Programming languages: compact, powerful, simple ...
Pick any two!
joel'dot'neely'at'fedex'dot'com