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

generalities of addresses and values...

 [1/11] from: rishi::picostar::com at: 9-Oct-2000 18:55


I'm a bit confused on how references work in Rebol. I wish there was a chapter in the rebol core manual dedicated on this alone. Perhaps someone could comment the general way addresses and values work in Rebol. Here is how I currently think it works...please correct me if I'm wrong. -all one-level series are passed/copied/attached by value. -all one-level objects are passed/copied/attached by value. -all one-level functions are passed/copied/attached by value. -all datatypes other than objects, series, and functions are passed/copied/attached by value. -all deep series are passed/copied/attached by reference. -all deep functions (functions within functions or blocks within functions) are passed/copied/attached by reference. -all deep objects (objects within objects or blocks within objects) are passed/copied/attached by reference. did I miss anything? Rishi

 [2/11] from: larry:ecotope at: 9-Oct-2000 19:46


Hi Rishi Well, there are a lot of issues raised by your questions. I am sure you will get a number of responses. I will limit myself to a couple of quick comments. In many ways REBOL is closely related to the Scheme language. 1) In the Scheme community, pass-by-value means the arguments to a function are evaluated by the interpreter before the function is called. This is true of REBOL as well. 2) In Scheme, all (well almost all) values are (at least conceptually) pointers (references). So an arg may be evaluated, but the value is a pointer. REBOL is similar, but more complicated. In Rebol, if a function has a string or block argument, the argument is evaluated before the function is called. But strings and blocks evaluate to themselves. In the case of blocks, the words within the block and recursively in all nested blocks are added to the symbol global table by the interpreter before the function is called, but no further processing is done. The block is then assigned to the local word defined in the function spec which is in the symbol table local to the function. But what is really passed into the function and assigned to the local arg word is a pointer to the string or block. Here is a short example which illustrates this behavior.
>> s: "abcdef"
== "abcdef"
>> f: func [x][remove x] >> f s
== "bcdef"
>> s
== "bcdef"
>> b: [1 2 3]
== [1 2 3]
>> f b
== [2 3]
>> b
== [2 3]
>> >> x ;x is a word local to the function f
** Script Error: x has no value. ** Where: x Notice that modifying the block or string referenced by the local variable x, also changes the original global value. To prevent that you would have to use COPY to create a new copy either in the function call or within the function itself. HTH -Larry ----- Original Message ----- From: <[rishi--picostar--com]> To: <[list--rebol--com]> Sent: Monday, October 09, 2000 11:55 AM Subject: [REBOL] generalities of addresses and values...
> I'm a bit confused on how references work in Rebol. I wish there was a
chapter in the rebol core manual dedicated on this alone. Perhaps someone could comment the general way addresses and values work in Rebol.

 [3/11] from: rishi:picostar at: 9-Oct-2000 22:59


ok. I think I get it now. Everything is basically done as a reference. Even setting words. This is much simpler than what I was thinking :-) ei: a: 5 b: a in this example, b is a reference to a (right?). The thing that was confusing me was that the copy function doesn't always create a new copy. In deep series, it creates a reference to copied value....strange... By the way, is there any way to prove that b is a reference to a ( in the above example) ? I know you can do it if you set the value of as a series datatype (by using insert or other series function). But how do you prove that b references a for number datatypes? Rishi Previously, you ([larry--ecotope--com]) wrote:

 [4/11] from: sharriff:aina:med-iq at: 10-Oct-2000 7:18


Good question Rishi, thanks larry for sheding a little light on that theme.. Sharriff Aina med.iq information & quality in healthcare AG Gutenbergstr. 42 41564 Kaarst tel.: 02131-3669-0 fax: 02131-3669-599 www.med-iq.de

 [5/11] from: brett:codeconscious at: 10-Oct-2000 18:39


> ok. I think I get it now. Everything is basically done as a reference.
Even setting words. This is much simpler than what I was thinking :-) Um...
> a: 5 > b: a > > in this example, b is a reference to a (right?).
Nope. b is set with the result of evaluating a.
>> a: 5
== 5
>> b: a
== 5
>> a: 3
== 3
>> a
== 3
>> b
== 5
> The thing that was confusing me was that the copy function doesn't always
create a new copy. In deep series, it creates a reference to copied value....strange...
> By the way, is there any way to prove that b is a reference to a ( in the
above example) ? I know you can do it if you set the value of as a series datatype (by using insert or other series function). But how do you prove that b references a for number datatypes? I showed above that b is not a reference to a. Here's another way to look at it. You could set the word "b" to have a value which is literally the word "a" - by doing this:
>> b: 'a
== a You could then see the value of the word "b" by
>> get 'b
== a or evaluting b
>> b
== a and combining
>> get b
== 3 Which evaluates b to a value, in this case a word, and then applies the get function to that value.

 [6/11] from: joel:neely:fedex at: 10-Oct-2000 21:47


Hello, Rishi! [rishi--picostar--com] wrote:
> ok. I think I get it now. Everything is basically done as a > reference. Even setting words. This is much simpler than what > I was thinking :-) >
Well... maybe not!
> ei: > > a: 5 > b: a > > in this example, b is a reference to a (right?). >
Not as I understand it. In the second line, the expression a is evaluated, yielding the value of 5. A copy of that value is bound to b (in the current context) by b: Note: When I said "a copy" above, I wasn't pretending to know how the REBOL interpreter works. I was trying to emphasize that all copies of 5 are interchangeable.
> The thing that > was confusing me was that the copy function doesn't always create > a new copy. In deep series, it creates a reference to copied value > ....strange... >
I think you're talking about the difference between b: copy a and b: copy/deep a (If I'm mistaken here, please let me know!) The issue is that series values are dealt with "by reference" so that one can do
>> a: ["This" "is" "a" "test"]
== ["This" "is" "a" "test"]
>> b: a
== ["This" "is" "a" "test"]
>> change next b "was"
== ["a" "test"]
>> a
== ["This" "was" "a" "test"] The word a contains a reference to the literal, four-string series in the first line. The second line binds to b a copy of the value of a , which means that b now has a copy of that reference. Since both of these references are to the same data structure, changing the state of that structure (through either reference) is visible via either/both. Now consider one-level copying. With
>> a: ["This" "is" "a" "test"]
== ["This" "is" "a" "test"]
>> b: copy a
== ["This" "is" "a" "test"]
>> change next b "was"
== ["a" "test"]
>> a
== ["This" "is" "a" "test"]
>> b
== ["This" "was" "a" "test"] it is (I hope) clear that THE BLOCK ITSELF was copied, not merely a reference to it. But... what does the block contain? Well, it contains four references! Blocks and strings are both series values, which are handled via reference. So changing the value to which b refers (as in the above example) doesn't affect the value to which a refers, BUT going one level deeper and changing a string (series value) to which both the (block) value of a and the (block) value of b refer will again be visible via either of the second-level references. Continuing after the interaction above, we can do
>> change/part skip b/1 2 "at" 2
== ""
>> a
== ["That" "is" "a" "test"]
>> b
== ["That" "was" "a" "test"] The way to ensure against such hidden connections is to do a deep copy, which recursively copies nested series values.
>> a: ["This" "is" "a" "test"]
== ["This" "is" "a" "test"]
>> b: copy/deep a
== ["This" "is" "a" "test"]
>> change next b "was"
== ["a" "test"]
>> a
== ["This" "is" "a" "test"]
>> b
== ["This" "was" "a" "test"]
>> change/part skip b/1 2 "at" 2
== ""
>> a
== ["This" "is" "a" "test"]
>> b
== ["That" "was" "a" "test"] After which we can see that
>> same? a b
== false
>> same? a/4 b/4
== false
>> same? a/4/1 b/4/1
== true
>> same? a/4/1 b/4/4
== true because two strings that spell the same word are not necessarily the SAME string. You can distinguish them by modifying one of them, and seeing whether the other is modified. However, any two copies of the letter #"t" are the same, because there's not any way to reach inside it and modify one of its parts.
> By the way, is there any way to prove that b is a reference to a > (in the above example) ? I know you can do it if you set the value > of as a series datatype (by using insert or other series function). > But how do you prove that b references a for number datatypes? >
It doesn't. If you wanted to prove that it did, you'd need to be able to modify a part of a numeric value in-place and show the change propagating. However, REBOL also does some other tricky things in that regard. Consider:
>> a: 1-Jan-2000
== 1-Jan-2000
>> b: a
== 1-Jan-2000
>> same? a b
== true
>> b/2: 10
== 10
>> b
== 1-Oct-2000
>> same? a b
== false
>> a
== 1-Jan-2000 Even though you can modify a component of a date value, doing do does not propagate. Therefore, one would conclude that the two date values are considered the same because they are being tested by value, rather than by reference. This is consistent with the results below:
>> same? "test" "test"
== false
>> same? 1-Oct-2000 2000/10/01
== true At this point, one would need to do similar tests for all REBOL datatypes to completely answer your question. The description of copy (with respect to the /deep refinement) leaves the impression that anything under the series! pseudotype would be a "reference", however.
>> series? ["This" "is" "a" "test"]
== true
>> series? "test"
== true
>> series? 1-Oct-2000
== false The best advice I can give you is to forget the concept of "address" that you may have from assembler, C, or any other low-level language. There just isn't any way to get at the "storage location" associated with a "variable" in REBOL -- in fact, I quoted those phrases just to emphasize that I'm speaking a foreign language here! Those concepts don't even exist in REBOL! -jn-

 [7/11] from: rishi:picostar at: 10-Oct-2000 22:29


I don't see how this proves that b is not a reference to a. Take this function for example: test: func [x y /in][ either in [insert x y][x: y] print ["in test function: " x] ] ; #1 X: 5 print ["x: 5"] test x 10 print ["after: " x] ;output for #1 x: 5 in test function: 10 after: 5 ;;#1 here it seems like the number x is passed by value since original x is not modified ;#2 x: "hello" print ["x: hello"] test x "bye" print x ;output for #2 x: hello in test function: bye hello ;;#2 here it seems like the string x is passed by value since original string is not modified. ;#3 x: "hello" print ["x: hello"] test/in x "bye" print x ;output for #3 x: hello in test function: byehello byehello ;;#3 here I am totally baffled since in #2 it is passed by value, but here it is actually modifying original value. passed by reference. This seems to contradict what you (brett) said about 'b not being a reference of 'a. Example #3 shows that value in variable x is referenced. Why is #2 passed by value and #3 passed by reference? This seem very inconsistent to me...but I'm sure reality is that I don't understand what is going on. It seemed to me that Larry implied that everything in rebol is passed by reference. but does not seem to be true as shown in above example. I don't know why this is so hard for me to grasp... It shouldn't be more complicated than c pointers! Rishi Previously, you ([brett--codeconscious--com]) wrote:

 [8/11] from: rishi:picostar at: 10-Oct-2000 23:37


Thanks Joel!! Please ignore (I know...too late) my previous message... Anyway, there is still one piece of the puzzle missing..
>> a: "test"
== "test"
>> b: a
== "test"
>> print b
test
>> b: "hello"
== "hello"
>> print a
test Here, when you set word 'b to 'a, I assume that 'a is dereferenced and then a copy of that reference is placed in b. So now both 'b and 'a should point to the same structure. Now when I set 'b to "hello", I change the address of the variable 'b to point to a new structure. oops...never mind...this is all making perfect sense now!!! So, here is a third attempt (third time is a charm...right?) to generalize how addresses and values work in rebol: All series! datatypes are treated as references and all other datatypes (numbers, dates, etc..) are treated as values. Has anyone confirmed this? I know I am not supposed to snoop around and figure out how this stuff works in REBOL, but it is just something I have to know... Rishi Previously, you ([joel--neely--fedex--com]) wrote:

 [9/11] from: lmecir:geocities at: 11-Oct-2000 9:02


Hi, Joel wrote:
> At this point, one would need to do similar tests for all REBOL > datatypes to completely answer your question. The description > of copy (with respect to the /deep refinement) leaves > the impression that anything under the series! pseudotype > would be a "reference", however. >
For some info you can see: http://www.rebol.org/advanced/mutable.r and http://www.geocities.com/lmecir.geo/evaluation.html Regards Ladislav

 [10/11] from: joel:neely:fedex at: 11-Oct-2000 8:04


PMBI, but your example actually demonstrates the "series values are reference values" issue nicely. [rishi--picostar--com] wrote:
> I don't see how this proves that b is not a reference to a. Take this function for example: > > test: func [x y /in][ > either in [insert x y][x: y] > print ["in test function: " x] > ] >
Before testing it, let's think about what it does. There are two locals x and y which are set from arguments. If the /in refinement is used, the second is inserted into the first; otherwise the first is bound to the second (in the context of the function!). To make the context explicit, I'm going to refer to the arguments as f.x and f.y (just making the context explicit -- sort of).
> ; #1 > X: 5 > print ["x: 5"] > test x 10 > print ["after: " x] >
So what we have is x:5 ; entering test [x 10] f.x: 5 ; obtained from x f.y: 10 ; obtained from literal f.x: 10 ; obtained from f.y, /in was not used print ["in test function: " 10] ; back from test [x 10] print ["after: " 5]
> ;output for #1 > x: 5
<<quoted lines omitted: 6>>
> test x "bye" > print x
What we should get is x: "hello" ; entering test [x "bye"] f.x: "hello" ; a copy of the reference in x f.y: "bye" ; obtained from literal f.x: "bye" ; f.x now refers the "bye" also ; referred to by f.y, /in was not used print ["in test function: " "bye"] ; back from test [x "bye"] print "hello" ; string referred to by x
> ;output for #2 > x: hello
<<quoted lines omitted: 6>>
> test/in x "bye" > print x
What we should get is x: "hello" ; entering test [x "bye"] f.x: "hello" ; a copy of the reference in x f.y: "bye" ; obtained from literal insert "hello" "bye" ; the string to which f.x refers ; is modified to be "byehello" ; (that is the same string referred to by x) ; because /in was used print ["in test function: " "byehello"] ; back from test [x "bye"] print "byehello" ; string referenced by x
> ;output for #3 > x: hello > in test function: byehello > byehello > > ;;#3 here I am totally baffled since in #2 it is passed by value, >
-- Whoa! Which "it"?!
> but here it is actually modifying original value. passed by reference. >
-- Again, which it?!
> This seems to contradict what you (brett) said about 'b not being a > reference of 'a. Example #3 shows that value in variable x is > referenced. >
NO!!! Example #3 simply shows that f.x refers to the same string as does x but NOT that f.x has anything to do with the global variable x itself! Since #3 modifies the shared string, upon return from test the modification is visible through x as it still refers to the same string.
> Why is #2 passed by value and #3 passed by reference? This seem very > inconsistent to me...but I'm sure reality is that I don't understand > what is going on.
It is totally consistent. In both cases a reference to a string was passed. In #2, that reference was simply REPLACED when the function evaluated x: y (which I've been rewriting as f.x: f.y to emphasize that it those words are in the context of the function). OTOH, in #3 that reference to a shared string was used to MODIFY THE REFERRED-TO STRING.
> It seemed to me that Larry implied that everything > in rebol is passed by reference. >
If I were wording the situation from scratch, I'd say something like, Everything in REBOL is passed by value. However, some REBOL values ARE references -- to data structures which may be accessed and modified using those references.
> but does not seem to be true as > shown in above example. I don't know why this is so hard for me to > grasp... It shouldn't be more complicated than c pointers! >
Why not? REBOL is a different language than c, so why should it behave like c? If you really want to think in terms of a low-level, machine-oriented language like c (which I do NOT advise), think of your example above in terms of pointer variables. You cannot (in REBOL) get a pointer TO a variable, but you can pass -- by value -- a copy of the pointer that a variable CONTAINS. For your function (reformatted with line numbers for explanation) func [ ; f#01 x y /in ; f#02 ][ ; f#03 either in [ ; f#04 insert x y ; f#05 ][ ; f#06 x: y ; f#07 ] ; f#08 print [ ; f#09 "in test function: " ; f#10 x ; f#11 ] ; f#12 ] ; f#13 we can evaluate x: "hello" ; g#01 test x "bye" ; g#02 print x ; g#03 x: "bye" ; g#04 test/in x "good" ; g#05 print x ; g#06 using the following pictures (pardon the clumsy ASCII art!). This is NOT standard REBOL notation, but just a way to try to depict one possible model of what's happening. The arrows show references, the {{...}} show internal data structures. I'll keep the f.x and f.y notation as well, to make clear which words we're talking about. (I don't want to try to draw contexts -- these pictures will be cluttered enough!) Each picture represents the state of the relevant variables after the statment has completed. g#01: x = {{string! 1 *}} | V {{#"h" #"e" #"l" #"l" #"o"}} Now x refers to a string (at position one) containing five characters. g#02/f#03: (i.e., just upon entry to the function...) x = {{string! 1 *}} | V {{#"h" #"e" #"l" #"l" #"o"}} ^ | f.x = {{string! 1 *}} {{#"b" #"y" #"e"}} ^ | f.y = {{string! 1 *}} f.in = {{none!}} Now the VALUE of f.x is an identical COPY of the VALUE of x ; both refer to same position of the same five character sequence. The value of f.y is a different string entirely. Since the /in refinement was not used in the call, its value is none , which means we'll skip ahead to f#07... g#02/f#07 x = {{string! 1 *}} | V {{#"h" #"e" #"l" #"l" #"o"}} f.x = {{string! 1 *}} | V {{#"b" #"y" #"e"}} ^ | f.y = {{string! 1 *}} f.in = {{none!}} The VALUE of f.x has been changed. Now it is a copy of the value of f.y which was initialized to a different string. g#02/f#12 Since the phrase beginning in f#09 refers to f.x , we get the side effect and final state... (output) in test function: hello x = {{string! 1 *}} | V {{#"h" #"e" #"l" #"l" #"o"}} f.x = {{string! 1 *}} | V {{#"b" #"y" #"e"}} ^ | f.y = {{string! 1 *}} f.in = {{none!}} and resume activity at the global level after g#02, at which point we don't have any access to the context of the function g#02 (output) in test function: hello x = {{string! 1 *}} | V {{#"h" #"e" #"l" #"l" #"o"}} Now we can continue with the next global statements g#03 in test function: hello (output) hello x = {{string! 1 *}} | V {{#"h" #"e" #"l" #"l" #"o"}} g#04 in test function: hello (output) hello x = {{string! 1 *}} | V {{#"b" #"y" #"e"}} g#05/f#03 in test function: hello (output) hello x = {{string! 1 *}} | V {{#"b" #"y" #"e"}} ^ | f.x = {{string! 1 *}} {{#"g" #"o" #"o" #"d"}} ^ | f.y = {{string! 1 *}} f.in = {{true!}} Now the VALUE of f.x is an identical COPY of the VALUE of x ; both refer to same position of the same five character sequence. The value of f.y is a different string entirely. Since the /in refinement WAS used in the call, its value is true , which means we'll skip ahead to f#05... g#05/f#05 in test function: hello (output) hello x = {{string! 1 *}} | V {{#"g" #"o" #"o" #"d" #"b" #"y" #"e"}} ^ | f.x = {{string! 1 *}} {{#"g" #"o" #"o" #"d"}} ^ | f.y = {{string! 1 *}} f.in = {{true!}} The insert action used the string reference of f.x to modify the string's value. Since the value of f.x was an identical COPY of the VALUE of x , both references still provide access to the modified character sequence. g#05/f#12 in test function: hello hello (output) in test function: goodbye x = {{string! 1 *}} | V {{#"g" #"o" #"o" #"d" #"b" #"y" #"e"}} ^ | f.x = {{string! 1 *}} {{#"g" #"o" #"o" #"d"}} ^ | f.y = {{string! 1 *}} f.in = {{true!}} and we can now resume global activity after g#05 (ignoring the inaccessible context of the function)... g#06 in test function: hello hello in test function: goodbye (output) goodbye x = {{string! 1 *}} | V {{#"g" #"o" #"o" #"d" #"b" #"y" #"e"}} Conclusion: Ignoring one level of indirection is fatal to an understanding of what's going on. Trying to make REBOL behave like a different language is fatal as well. Notice that in none of the pictures above did we have any arrows pointing to variables. While one may be able to draw such a picture, it has no meaning in REBOL. Hope this helps! -jn-

 [11/11] from: joel:neely:fedex at: 11-Oct-2000 9:22


[rishi--picostar--com] wrote:
> All series! datatypes are treated as references and all other > datatypes (numbers, dates, etc..) are treated as values. >
That is my understanding, given the way you are using the terms reference and "value". It could also be said that series values are mutable, while other values are immutable.
> Has anyone confirmed this? >
I haven't had time to do all the "REBOL particle physics" myself, and don't know whether anyone else has tried all the possibilities either.
> I know I am not supposed to snoop around and figure > out how this stuff works in REBOL, but it is just something I have > to know... >
To the contrary! You SHOULD "snoop around" and confirm for yourself that you understand how things are behaving in REBOL! That's likely the best way to learn, and to confirm that what you think you've learned is true. Keep REBOLving! -jn-

Notes
  • Quoted lines have been omitted from some messages.
    View the message alone to see the lines that have been omitted