Request: arguments by reference

P

Pedro Silva

Would be possible to include the option to pass arguments by reference
instead of by value?

def swap(a, b)
tmp = a
a = b
b = a
end

a = "A"
b = "B"
swap(a, b)
puts a, b # "A", "B"

Because Ruby passes arguments by value any attribution will change only
the arguments not the variables. My sugestion is to use some way of
indicating that the argument is a reference and that would allow the
above example to work.
I don't know if this will mess things up, but I guess the difference is
only instead of creating a new variable, "tell" the intrepeter to use
the variable passed as argument. But that can break something...

I know the above example can be done like 'a, b = b, a', but this always
obliges to set things directly and never allow to use functions, that,
in my opinion, is a limitation. The actual way forces the programmer to
know if any particular method creates or not a new object. For instance:

def append_str(str, append)
str << append
end

def add_str(str, add)
str += add
end

a = "A"
b = "B"

append_str(a, " + something")
add_str(b, " + nothing")

puts a, b # "A + something", "B"

<< operator changes the object itself so a will be changes, += creates a
new object so b won't be changed. Taking into account that Ruby uses
mainly references for each object (fixnum and company are the
exceptions) I hope this would be possible to include.
 
T

Thomas B.

Pedro said:
Would be possible to include the option to pass arguments by reference
instead of by value?

I think not. In Java you cannot pass by reference, and that's not
because Java is a poor language where things cannot be done easily.
That's because Java enforces other way of programming than, say C. It's
Object Oriented programming, namely.

Passing by reference is adding mess. The = sign after a variable name
assigns a new value to this variable, and let this be that way.
Similarly += and the family.

If you need badly the variables to really change values, do what should
be done in an object oriented language: wrap them in classes, and add
accessors. That's the way you'd also do it in Java.
The actual way forces the programmer to
know if any particular method creates or not a new object.

In fact, programming forces the programmer to know how to programme. And
knowing what creates a new object and what not, is part of this
knowledge. And in Ruby it's not very hard to guess.
Taking into account that Ruby uses
mainly references for each object (fixnum and company are the
exceptions) (...)

In fact Ruby always passes the reference to an object by value, no
matter if it is Fixnum or whatever. The only difference is that Fixnums
(and some others) are immutable, so they simply do not have methods like
<< that change their values in-place. Ruby behaves the same way with any
class of arguments, it's the class itself that does or does not allow an
in-place change.

TPR.
 
T

Thomas B.

Thomas said:
The = sign after a variable name
assigns a new value to this variable (...)

Sorry. What I said is not what I meant, and is not correct. This
sentence ought to be:

The = sign after a variable name assigns a new variable to this name
(...)

TPR.
 
P

Pedro Silva

Hi,
Well, of course there is some performance penalty, but I guess it is not
that fatal. I don't know the actual implementation of accessors in Ruby,
but I think that the time penalty could be really low, and the memory
penalty can be reduced by encapsulating logical group of variables in
one class (which should be done anyway). I think that if they decided
not to include passing by reference in Ruby (and also in Java), then
they had some good solution in mind, and this solution cannot be as bad
as you paint it.

In my opinion there are essentially two reasons:
1 - Everything is supposed to be an object;
2 - Anything that needs to be altered is inside the passed object.

If everything is an object than everything is "encapsulated", so when
you pass the object's reference value you can change that object in any
way you want.
If you need to swap anything, that must be done inside any particular
object.

I guess they are counting on this two things. But once again, if this
rules were perfect Java won't have primitive data types, nor Ruby would
have immutable objects.
Also I think that in a well designed program, the situations where you
need such behaviour would not exist. Of course performance is important,
but I think that still the most important thing is the ability to create
a nice, readable and structured code, so I would definitely choose
encapsulating over changing the language.

That would be almost true if there weren't primitives nor immutable
objects, but that's not the case. I may be wrong, but who decided that
these mecanisms are enough was thinking in the solution you gave, that
represents a small amount of cases. The other solution (in Ruby) is to
return as result all altered variables in a specific order and assigned
them to variables you want to alter (I guess it's known as
call-by-value-return).

The main need for references is to allow primitive/immutable types to be
treated "as objects". Even if the only thing that Ruby used to implement
references was the object encapsulation, at least you have that option
and don't need to be doing that all the time it needs to be done. Being
inside Ruby it would be certainly faster than user made code. If you
think in C pointers or C++ references that's what they really are -
"capsules". I think it's preferable to have this option even if it isn't
as performant, but the programmer has the choice.

Pedro.
 
T

Thomas B.

Pedro said:
The main need for references is to allow primitive/immutable types to be
treated "as objects". Even if the only thing that Ruby used to implement
references was the object encapsulation, at least you have that option
and don't need to be doing that all the time it needs to be done. Being
inside Ruby it would be certainly faster than user made code. If you
think in C pointers or C++ references that's what they really are -
"capsules". I think it's preferable to have this option even if it isn't
as performant, but the programmer has the choice.

So I think that the best solution could be not to add syntax for passing
by reference, but to add types like MutableFixnum (and others), that
would behave exactly like Fixnum, plus they would have method replace,
working a bit like Array#replace - changing the value without creating a
new object. In this way, all old code would work as before, and as fast
as before, and also there would be no chance of accidentally changing
value of an object that should not be changed (like calling
a.b.replace(x) even though a.b= is not defined and it is crucial for the
program that it is not). You would be able to change only object
declared as MutableSomething. It wouldn't also mess things up with =.

Probably not in 1.9, but maybe later it could make some sense to think
about how to implement it in the core.

Th.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,822
Latest member
israfaceZa

Latest Threads

Top