Function Variable and Return Value References

In C++, one thing that is certain is that all variables passed into functions and all return values are actually copies. Therefore, the functions can't manipulate their arguments directly. As everyone knows, the easiest way to get this effect is to pass in by reference. This way a copy is not made; the actual variable is passed in, allowing direct modification. A similar idea can be used with return values or even without a function at all.

The question is, how exactly does ruby behave in this respect? I haven't quite figured out what the rules are. It appears that Fixnum and basically every user-made object are always passed by value, and can not reference each other. However, arrays seem to be passed into functions by reference, and returned by value, though the objects they contain are copied.

At first, I thought variables were always pointers, and things such as a = b meant that if you change a, you change b. It seems now that this is in fact never the case. So that brings me to my second question: what are the purpose of the methods dup and clone? I thought they would be useful if you needed to assign copies rather references, but it seems that objects are copied by default when assigned. Can someone please explain this to me?

···

---------------------------------
Yahoo! FareChase - Search multiple travel sites in one click.

Hi,

At Sat, 12 Nov 2005 11:12:01 +0900,
Eric Hofreiter wrote in [ruby-talk:165383]:

At first, I thought variables were always pointers, and
things such as a = b meant that if you change a, you change b.

You need to distinguish variables and objects.

···

--
Nobu Nakada

Eric Hofreiter wrote:

The question is, how exactly does ruby behave in this respect?
I haven't quite figured out what the rules are.

FAQ [4.5: How are arguments passed?]

It appears that Fixnum and basically every user-made object are
always passed by value, and can not reference each other.

The rules of assignment apply (ref FAQ).

However, arrays seem to be passed into functions by reference,
and returned by value, though the objects they contain are copied.

That's a bit of a muddle (if I might be so bold ;).

At first, I thought variables were always pointers, and things
such as a = b meant that if you change a, you change b.

a and b now reference the same object -- that's right.

It seems now that this is in fact never the case.

Oh, no :slight_smile:

So that brings me to my second question: what are the purpose of
the methods dup and clone? I thought they would be useful if
you needed to assign copies rather references, but it seems that
objects are copied by default when assigned.

There's no copying on assignment - that's the same reason you
may need dup/clone.
I can usually manage to get most of the way through a prog without
resorting to dup/clone by using the feature that many methods
return a modified object (a modified copy of the target).

Can someone please explain this to me?

I'm not very chatty but the above might get you started.

daz

Eric Hofreiter wrote:

In C++, one thing that is certain is that all variables passed into functions and all return values are actually copies. Therefore, the functions can't manipulate their arguments directly. As everyone knows, the easiest way to get this effect is to pass in by reference. This way a copy is not made; the actual variable is passed in, allowing direct modification. A similar idea can be used with return values or even without a function at all.
The question is, how exactly does ruby behave in this respect? I haven't quite figured out what the rules are. It appears that Fixnum and basically every user-made object are always passed by value, and can not reference each other. However, arrays seem to be passed into functions by reference, and returned by value, though the objects they contain are copied.
At first, I thought variables were always pointers, and things such as a = b meant that if you change a, you change b. It seems now that this is in fact never the case. So that brings me to my second question: what are the purpose of the methods dup and clone? I thought they would be useful if you needed to assign copies rather references, but it seems that objects are copied by default when assigned. Can someone please explain this to me?

You're on the right track, you just have a few misunderstandings.

First of all, variables in Ruby *do* hold references to objects
(except in the cases where the values are "immediate" -- Fixnum
for example).

But remember that assignment is not a method in Ruby. Assignment
can't be overridden or any such thing. (Well, an attr_writer
gives you something that looks like assignment, but it's really
just a bit of syntax sugar.)

So any operation that actually *changes* the object will behave
as you expect.

   a = "Hello"
   a = b
   b << " there!"
   puts a # "Hello there!"
   puts b # "Hello there!"

However, any operation that binds a variable to a new/different
object won't show that effect.

   a = "Hello"
   a = b
   b += " there!"
   puts a # "Hello"
   puts b # "Hello there!"

You might think at first glance that x << y and x += y do the
same thing for strings. And indeed they result in the same value.

But x += y is just syntax sugar for x = x + y (i.e., they mean
*exactly* the same thing). So += is actually an assignment, and
thus doesn't change an object -- it just binds a variable to a
new or different object.

The example shown above would work the same way for arrays. But
it wouldn't make any sense for Fixnums -- they are immediate
values, and anyhow are immutable. (All immediate values are
immutable, but some "real objects" are immutable also -- e.g.,
a Time value.)

Does that help some??

Hal

Actually, I think of ruby variables as pointers (like a void * in
C/C++ - no particular pointer type).

Looking at Hal's example, here's how you might equate C++ and ruby (my
C++ isn't so good):

  a = "Hello" # string a0 = "Hello"
                                        # string *a = &a0
  b = a # string *b = a
  c = a # string *c = a
  b += " there!" # b = &(*b + " there!")
  puts a # cout << *a
  # => "Hello"
  puts b # cout << *b
  # => "Hello there!"
  puts c # cout << *c
  # => "Hello"
  c << " world!" # c->append(" world!")
  puts a # cout << *a
  # => "Hello world!"
  puts b # cout << *b
  # => "Hello there!"
  puts c # cout << *c
  # => "Hello world!"

For all but immediate objects this is pretty much how variables are
implemented - as object pointers/references. Even for immediate
objects (Fixnum, Symbol, true, false, nil), you can also think of them
the same way. Since immediate objects are immutable and don't require
much data (at most 31 bits), they can be encoded right into the
pointer directly (all other normal object pointers are aligned to
32-bit boundaries so that the bottom 2 bits are 0 - immediates may put
ones here).

What you can't easily do is get a reference to a variable itself.
Since variables hold references to objects, you'll find this is seldom
wanted. I have had several occasions though and had to find another
(less elegant) way around. It would be kind of nice if there was a
heavier weight variable (like C++ reference variable) where you could
control what methods to use for getting and setting the variable.
Some other pure OO languages (i.e. self) treat a variable as an object
with get and set methods. With ruby they are lightweight, which makes
it easy to make them efficient.

···

On 11/11/05, Eric Hofreiter <erichof425@yahoo.com> wrote:

At first, I thought variables were always pointers, and things such as a = b meant that if you change a, you change b. It seems now that this is in fact never the case.