Home   Archive   Permalink

annoying rebol's behaviour

I always find this Rebol behaviour very annoying actually it's my biggest pet peeve .i.e your local variable gets overriden when you call your function and then keeps the value for the next run as well. can't this be fixed ?
test: func [ input /local s ] [ s: "hello" append s input ]
>> test "joe"
== "hellojoe"
>> test "tom"
== "hellojoetom"
test "tom" should give me "hello tom"
I know we have to do "copy" to work around that problem, but this is a hack, it goes against the principle that your program should do exactly as we write. i.e if I have a statement s: "dear" in the body of my function, every time you call the function , it should execute s: "dear" and assign "dear" to s.    
this brings an element of unpredictability to the outcome of our code, if the language can override what I want my code to do.
what does the community think about that?

posted by:   yuem       30-May-2010/9:31:54-7:00

You know this is discussed several times, it always confusing beginners mind, as it was for me.
But "copy"ing is not a hack or workaround actually, it is a must.
When you think it is just a string, it look you are right. But it is a series actually.
And variables are always "point" to series in Rebol.
Otherwise when you do this:
b: [a b c]
b: next b
Then you will lost the original b, and you would have only [b c] as b.
or c: at b 3
c would be a new variable. it is so, but actually it is just points to another position inside b.
so b and c points to the same series.
equal? head b head c
>> true
It is all same for the strings and other series types.
And it is a way to use static variable in a function.
f: func [/local x] [x: [5] print first x change x (first x) + 1]
>> 5
>> 6
otherwise we would need a /static like /local.
But I agreed with you, it is confusing.

posted by:   Endo       30-May-2010/9:52:39-7:00

my point is that the statement s: "dear" should be executed every time my function is executed, even if it is a series, it should reinitialize the series.
>> s: [ 1 ]
== [1]
>> append s 2
== [1 2]
>> s: [ 1 ]
== [1]
the lines above are what I get from the rebol console
you see what I mean, s should become 1 again , as it should execute the latest assignment again. it's not an append statement, it's an assignment. It doesn't matter whether it is a series or a string.

posted by:   Yuem       30-May-2010/10:05:39-7:00

Yuem, in your particular case, that seems like a reasonable statement, but Endo is right. Persistent series are essential to the way REBOL works, and that characteristic enables many other valuable features of the language. In your case, it's a trivial thing to get used to, and a small price to pay for other benefits. Yes, it's different then you may expect at first, when coming from other languages, but it's perfectly intuitive when you get used to it :)

posted by:   Nick       30-May-2010/11:10:53-7:00

REBOL works by aggressively reusing series to easily allow your scripts to run faster and save memory. This is why copying is an explicit action in most cases. In fact, the first REBOL version 1.0 was written to work the other way around and it ran 30 (thirty!) times slower than REBOL 2.
So, it's not a hack. It's a basic REBOL design philosophy and it works even more aggressively in REBOL 3 and there is a function type to explicitly state what you want in your example.

posted by:   Henrik       30-May-2010/15:17:41-7:00

That's an interesting issue...
Should I "copy" every literal? I.e., should I write
    return copy false
rather than
    return false
and should I even "copy" literal arguments before passing them as argument to a function?
Kind regards,
Andreas Rozek

posted by:   Andreas Rozek       12-Jun-2010/1:22:38-7:00

I just learned that copy expects arguments of series, port or bitset anyway - I therefore assume, that only literals of such types have to be copied?

posted by:   Andreas Rozek       12-Jun-2010/1:52:12-7:00

Yes. This part of the manual may help you understand better - http://www.rebol.com/docs/core23/rebolcore-4.html
(It is still relevant even though it is quite old.)

posted by:   Peter W A Wood       12-Jun-2010/6:19:24-7:00

Hmmm, Peter: are you sure? While the document you mentioned contains valuable information, I did not find anything dealing with the question when to "copy" a literal and when not (unless somebody is "reading between the lines")

posted by:   Andreas Rozek       12-Jun-2010/14:51:45-7:00

from the rebol core manual:
"Copying is also important for use with functions that modify the contents of a series. For instance, if you want to change the case of a string without modifying the original, use the copy"
or the complete guide (which is old but still very useful)
there is also a pdf version it's still like my holy bibble.
and yes, you should always copy if your variable is a series type variable, like strings, ports, images, blocks. for other values copy will fail.

posted by:   Endo       12-Jun-2010/16:24-7:00

Whenever you want to create a fresh, new, empty block or string, or if you don't want to affect an existing block or string, use "copy".
I.e., usually:
     x: copy []
Instead of:
     x: []
Here's a common mistake:
unexpected: [
     empty-variable: ""
     append empty-variable "*"
     print empty-variable
do unexpected
do unexpected
do unexpected
; should be:
expected: [
     empty-variable: copy ""
     append empty-variable "*"
     print empty-variable
do expected
do expected
do expected

posted by:   Nick       12-Jun-2010/16:33:08-7:00