Basic question: passing a modifiable argument to a routine

Arguments to subroutines seem to be passed by value in ruby

$ irb
irb(main):001:0> def woof(a)
irb(main):002:1> a += 2
irb(main):003:1> end
=> nil
irb(main):004:0> b = 5
=> 5
irb(main):005:0> woof(b)
=> 7
irb(main):006:0> b
=> 5
irb(main):007:0>

so how do I pass a variable to a routine if I want the routine to
modify the variable. In C I would say:

void woof(int *a) {
*a += 2;
}
int b = 5;
woof(&b);
printf("%d\n", b);

would output 7.

lalawawa wrote:

Arguments to subroutines

They’re called functions or methods in Ruby.

seem to be passed by value in ruby

Nope. They’re passed by reference – or rather, they’re object
references passed by value, like in Java.

$ irb
irb(main):001:0> def woof(a)
irb(main):002:1> a += 2
irb(main):003:1> end
=> nil
irb(main):004:0> b = 5
=> 5
irb(main):005:0> woof(b)
=> 7
irb(main):006:0> b
=> 5
irb(main):007:0>

Yes, because += makes a reference to a different object.

so how do I pass a variable to a routine if I want the routine to
modify the variable.

Don’t. Instead, assign the return value to the variable, or use a bang!
method on an object.

In C I would say:

void woof(int *a) {
*a += 2;
}
int b = 5;
woof(&b);
printf(“%d\n”, b);

would output 7.

b = woof(b)

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]

On Sun, Jan 17, 2010 at 7:00 PM, lalawawa [email protected] wrote:

=> 7
irb(main):006:0> b
=> 5
irb(main):007:0>

They are actually pass by reference, as in Java and C++, or arrays in C.

For example
def woof(a)
a << “e”
end

a = “bcd”
woof(a)
a # => “bcde”

Your example does not reflect this, because of two issues.

The first is that numbers are immutable, so even though you can modify
the
objects themselves, you can’t modify numbers.
The second is that += does not modify the object itself, it modifies the
label. It is the same as saying a=a+1
This is because of the first reason, since they are immutable you must
do
a=a+1 instead of a++

On Sun, Jan 17, 2010 at 7:00 PM, lalawawa [email protected] wrote:

would output 7.

Honestly, I don’t ever really find myself in situations where I need to
do
this, you may need to rethink your approach.
Regardless, I suppose I can think of three alternatives.

Alternative 1 is to use an instance variable, don’t do this trivially,
they
will pollute your namespace.
def woof
@a+=2
end

@a = 2
woof
@a # => 4

Alternative 2 is to have the method return the new value ie, it seems a
little messy, though, since it requires code outside to know that it
needs
to assign results in some given manner.

def woof(a)
a+2
end

a = 2
a = woof(a)
a # => 4

Alternative 3 is to wrap the variable in a mutable object, like Java’s
Integer (except that isn’t mutable either :P), but I can’t seem to come
up
with a way of doing this that I don’t hate.

If you care to show your example, we might be able to spot a more Ruby
approach.

When you say that += creates a different object, then are you saying
that when I do

a = 0
while a < 1000000
a += 1
end

it creates a million different objects and garbage collects most of
them? Isn’t that horribly inefficient for just doing integer
arithmetic?

lalawawa wrote:

When you say that += creates a different object, then are you saying
that when I do

a = 0
while a < 1000000
a += 1
end

BTW, the more idiomatic way of doing this would be something like
1.upto(1_000_000).each do |n|

something

end

it creates a million different objects and garbage collects most of
them? Isn’t that horribly inefficient for just doing integer
arithmetic?

Actually no. For performance reasons, Fixnums are implemented as
singletons in all Ruby environments that I’m aware of.

But yes, try playing around with the object_id method and you’ll see
interesting things.

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]

On Mon, Jan 18, 2010 at 9:25 AM, lalawawa [email protected] wrote:

arithmetic?
In this case, those integers are all Fixnums which are represented by
immediate values, so no allocation or GC is involved.

Of course if you are really concerned about efficiency you can always
do that calculation as:

a = (1000000*1000000 + 1000000) / 2


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: Rick DeNatale - Developer - IBM | LinkedIn

On Jan 18, 10:47 am, Rick DeNatale [email protected] wrote:

them? Isn’t that horribly inefficient for just doing integer

Rick DeNatale

Blog:http://talklikeaduck.denhaven2.com/
Twitter:http://twitter.com/RickDeNatale
WWR:http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn:Rick DeNatale - Developer - IBM | LinkedIn

Well, I’m trying to understand. If I do

a = 0
while a < 1_000_000
a += 1
end

a.object_id at the end is 2000001. Does this mean a 2 million
instances of fixnum are in existance, just not garbage collected?

2010/1/18 lalawawa [email protected]:

Well, I’m trying to understand. If I do

a = 0
while a < 1_000_000
a += 1
end

a.object_id at the end is 2000001. Does this mean a 2 million
instances of fixnum are in existance, just not garbage collected?

No, Fixnums are “immediate values” which means there is just the
object reference. So there is no object allocated on the heap where
the reference points to. We had recent discussions about this and
there is a nice article on Wikipedia that explains how this works:

Kind regards

robert

lalawawa wrote:

On Jan 18, 10:47�am, Rick DeNatale [email protected] wrote:

them? �Isn’t that horribly inefficient for just doing integer

Rick DeNatale

Blog:http://talklikeaduck.denhaven2.com/
Twitter:http://twitter.com/RickDeNatale
WWR:http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn:Rick DeNatale - Developer - IBM | LinkedIn

Well, I’m trying to understand. If I do

a = 0
while a < 1_000_000
a += 1
end

a.object_id at the end is 2000001. Does this mean a 2 million
instances of fixnum are in existance, just not garbage collected?

You can think of it that way (1 million, actually – Fixnums only use
odd object_ids), but in fact Fixnums are implemented more efficiently
than that, at least in MRI. You shouldn’t run into performance issues
with Fixnums.

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]

2010/1/18 lalawawa [email protected]

them? Isn’t that horribly inefficient for just doing integer
arithmetic?

Apart from what Rick already said - the funny thing is: the fact that
Ruby works this way (i.e. has a uniform object model as opposed to
Java which does have non object types) makes a lot of things easier.

And with the optimization Rick mentioned it even isn’t too inefficient

  • something that Java programmer haunts when they use object types
    like java.lang.Integer and friends. I remember an article which
    elaborated on that design flaw of Java but I can’t seem to find it
    right now. Maybe Charly has a link handy.

Kind regards

robert