basic question: passing a modifiable argument to a routine

L

lalawawa

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.
 
M

Marnen Laibow-Koser

lalawawa said:
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
(e-mail address removed)
 
J

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

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>

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++

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.

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.
 
L

lalawawa

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?
 
M

Marnen Laibow-Koser

lalawawa said:
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
(e-mail address removed)
 
R

Rick DeNatale

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

a =3D 0
while a < 1000000
=A0a +=3D 1
end

it creates a million different objects and garbage collects most of
them? =A0Isn't that horribly inefficient for just doing integer
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 =3D (1000000*1000000 + 1000000) / 2

--=20
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale
 
L

lalawawa

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:http://www.linkedin.com/in/rickdenatale

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?
 
R

Robert Klemme

2010/1/18 lalawawa said:
When you say that +=3D creates a different object, then are you saying
that when I do

a =3D 0
while a < 1000000
=A0a +=3D 1
end

it creates a million different objects and garbage collects most of
them? =A0Isn'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
 
R

Robert Klemme

2010/1/18 lalawawa said:
Well, I'm trying to understand. =A0If I do

a =3D 0
while a < 1_000_000
=A0 =A0a +=3D 1
end

a.object_id at the end is 2000001. =A0Does 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:

http://en.wikipedia.org/wiki/Tagged_pointer

Kind regards

robert

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 
M

Marnen Laibow-Koser

lalawawa said:
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
(e-mail address removed)
 

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

Forum statistics

Threads
473,968
Messages
2,570,154
Members
46,702
Latest member
LukasConde

Latest Threads

Top