[REBOL] generalities of addresses and values... Re:(5)
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
> 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
>
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
> 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
>
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-