On 03.10.2010 19:49, Caleb Clausen wrote:
> On 10/2/10, Josh Cheek<josh.cheek / gmail.com>  wrote:
>> On Sat, Oct 2, 2010 at 10:57 PM, Caleb Clausen<vikkous / gmail.com>  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/