From: Robert Klemme Date: 2010-10-04T04:15:22+09:00 Subject: Re: Pass by reference and copy on write On 03.10.2010 19:49, Caleb Clausen wrote: > On 10/2/10, Josh Cheek wrote: >> On Sat, Oct 2, 2010 at 10:57 PM, Caleb Clausen wrote: >> >>>> It's just that in the case of Fixnums (and a few other things) it is >>>>> not possible to have references at all; such objects are always stored >>>>> (and passed) by value >>>> >>>> If it were pass by value, I would expect it to make a new object each >>> time >>>> it passes that object. >>> >>> It does make a new object when you pass a Fixnum as a parameter; the >>> Fixnum is copied into a different cell in memory. Fixnums are >>> compressed so that the Fixnum value is stored within the reference to >>> it. So I guess Fixnums are kinda value and reference all wrapped up in >>> one burrito. >>> >>> Convinced? I'm not sure I am. >>> >>> >> How about in this case? >> >> def add_ivar(remote) >> remote.instance_eval do >> @ivar = "added in function" >> end >> nil >> end >> >> local = 1 >> add_ivar(local) >> local.instance_variables # => [:@ivar] >> >> Here, if I understand you, you are saying that add_ivar's object "remote" >> and main's object "local" are not the same object, because it creates a new >> object when we pass local as a parameter. However, in add_ivar, we open up >> remote and add an instance variable to it. At this point, that ivar should >> exist on the add_ivar's "remote" and not on main's "local". When we return, >> we pass back nil, just to ensure that add_ivar's "remote" is never an arg, >> and should simply be discarded when scope leaves the add_ivar method. >> However, back in main, we can see that the ivar that it added does in fact >> exist on main's "local". How did it get there, since it is a different >> object than the one we mutated? > > I would say that passing a fixnum does indeed make a new 'copy' of it, > for that method call. While this is technically true (because the reference actually *is* the Fixnum value) I think this is a bad way to express it. The reason is that it looks into implementation details of the interpreter when one tries to describe a phenomenon of the language Ruby. It actually complicates things more than necessary which IMHO hinders understanding. I always look at it this way: assignments copy object references. A method call also does assignments (to method parameters in this case). Whether you are affected by any aliasing effects mainly depends on the behavior of an object's methods. If they modify the instance then of course everyone with the same object reference will see the effect. If they only return new references instead of modifying the instance (as in the case of Fixnum#+ and others) there are no aliasing effects. > BUT, since, as you say below, fixnums are > singletons, and there's only ever one 'instance' of any given fixnum. > Changes to the fixnum's state affect the value seen by the caller as > well. > > There doesn't need to be a method call to see the paradox of fixnum > state sharing in effect. Watch: > > var1=1 > var2=1 #a fresh, new copy of the fixnum 1 I'd say it's not a copy of the Fixnum. It's a copy of the reference to the singleton instance. Basically you can look at "1" as an expression which returns a reference to an instance - and it happens to be implemented in a way as to always return a reference to the same instance for the same literal. It's different for "'1'" which always constructs a new String instance. > var1.instance_eval{@x=:foo} > p var2.instance_eval{@x} #=>:foo #whoa!, var1 and var2 share state! > > But this same behavior is not seen with other numeric classes, like > Float and Bignum. I just noticed there seem to be some optimizations going on at least since 1.8.7 for Floats: irb(main):002:0> 5.times { p 1.0.object_id } 137086642 137086642 137086642 137086642 137086642 => 5 irb(main):003:0> 1.0.object_id => 137075106 irb(main):004:0> 1.0.object_id => 137055198 irb(main):005:0> Apparently the interpreter creates only one float per code location. > Frankly, I think that it should not be possible to set instance > variables on the built-in immutable classes: Fixnum, Bignum, > true/false/nil, Float, Symbol. That would at least reduce the potential for confusion. > I like Rick's terminology: pass by object reference. I think that > makes it a little clearer what is really going on. Then if you > understand the subtleties of how Fixnums are actually packed into > their object references, you'll understand what is going on, and why > they behave differently than other classes. I agree. But I think when talking about the Ruby language it is not necessary - and in fact causes more confusion than clarity - to talk about the subtleties of Fixnum internal handling. It is sufficient to state that all integer expressions up to a certain size yield singleton instances. Actually, as a user of the Ruby language that does not write extensions in C you cannot tell that the interpreter does not allocate an instance on the heap but derives the value from the reference itself. Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/