[Note: parts of this message were removed to make it a legal post.]
I'm not sure about a few things in your post. You say:
On the other hand, in a pass-by-reference language the situation is:
+-----+
| a | --+
+-----+ | +-----+
+--> | 1 |
+-----+ | +-----+
| b | --+
+-----+
That's why you can implement swap in such languages.
But that is how Ruby does it. I've been playing with it, and think that
Fixnums are always singleton in Ruby (meaning only ever one instance of a
given Fixnum), so lets use Strings to see.
var1 = "abc"
var2 = var1
var1.object_id == var2.object_id # => true
var1[1] = "x"
var1 # => "axc"
var2 # => "axc"
Clearly, they are both referencing the same object, as they have the same
object_id, and when var1 mutates the object, var2 also sees the mutation. So
according to your definition here, Ruby is pass by reference.
Also, I don't understand what you mean by implementing a swap. Both
variables reference the same object, there doesn't seem to be anything to
swap.
*But I can change the integer a variable holds by passing a pointer in C!*
That is true, but you are not passing the integer, you are passing a
pointer to the integer. Since C is pass-by-value, if you had a variable
holding the pointer before the call, you can be totally certain the variable
will hold the same exact pointer after the call.
It seems that you are differentiating them based on whether the pointer is
passed implicitly or explicitly. In other words, in C, you know you passed
the pointer, in Perl, the language did it for you. As C++ does the same
thing that I think you are saying Perl does, here is a gist showing that
C++'s references generate the same assembly source as C's pointers.
http://gist.github.com/240499
*Summary*
The terms pass-by-value and pass-by-reference are about links from names to
storage areas, they have nothing to do with the references or pointers of
your language.
I don't really understand what is meant by "references or pointers of your
language"
-----
When I think of pass by value and pass by reference, using your diagram,
above, I mean that pass by reference passes the value of the variable a,
which is a memory location (reference) for the object 1. This is juxtaposed
with what I would call pass by value, where it passes the object 1 itself, a
costly maneuver given the size of some objects. Here is an example.
#include <stdio.h>
typedef struct { int attribute; } expensive_struct;
void print_struct( char* context , expensive_struct *s ) {
printf( "%-30s s is at 0x%lx, and has the attribute %d\n" ,
context , (unsigned long int)s , s->attribute );
}
void pass_by_ref(expensive_struct *s) {
s->attribute++;
print_struct( "inside pass_by_ref" , s );
}
void pass_by_value(expensive_struct s) {
s.attribute++;
print_struct( "inside pass_by_value" , &s );
}
expensive_struct
pass_by_value2(expensive_struct s) {
s.attribute++;
print_struct( "inside pass_by_value2" , &s );
return s;
}
int main() {
expensive_struct s = {0};
print_struct( "main, initial" , &s);
pass_by_ref(&s);
print_struct( "main, after pass by ref" , &s);
pass_by_value(s);
print_struct( "main, after pass by value" , &s);
s = pass_by_value2(s);
print_struct( "main, after pass by value2" , &s);
return 0;
}
Notice in pass_by_ref, the memory address is the same, they are both
pointing to the same object, like your diagram above. And main sees the
change to that object that pass_by_ref made. The memory address (reference)
was passed.
However, in pass_by_value, the memory address is different, and main cannot
see changes to the object that pass_by_value has made. This is because the
object (value) was passed instead of the reference.
To get around this, pass_by_value2 does the same thing, but passes the value
back, which is then written over the old value. Since s is an expensive
struct, maybe containing large quantities of data, this is a costly thing to
do. It would be so much more efficient if we only had to pass the 4 or 8
bytes that our system needed to keep track of a memory location. Then we
could allow our function to work on the object (value) while only having to
incur the expense of passing the address (reference).
-----
Then, within pass by reference, I think there are two kinds of references
that can be passed. The C++ / (based on your description) Perl style, where
the reference passed is to the memory address of the variable, or Ruby /
Java style, where the reference passed is to the memory address of the
Object. The difference here is that C++ / Perl have to dereference twice in
order to get to the object, and have the added capacity to alter the
variable itself.
So in C++ / Perl, it looks like: ref2 --> ref1 --> "object"
Where as in Java it looks like: ref2 --> "object" <-- ref1
And C++ gives you the syntax such that every time you use ref2, you feel
like you are using ref1, by dereferencing ref2 each time you use it.
So, I say that Ruby does pass by reference the Java way, and Perl does pass
by reference the C++ way. And C can do both, and can also do pass by value.