On Wed, 09 Apr 2008 13:55:34 -0500, Hexren wrote:

> The code posted below actually modifies the array in the object.
> Am I doing something wrong here ?
> If not, this should imho be included in the doc. It seems 
> counterintuitive to me ;)

[snip]

> ----------------------------------
> class AttrReaderErr
>    attr_reader :entries
>    def initialize()
>      @entries = [0,1,2]
>    end
> end
> 
> showcase = AttrReaderErr.new
> 
> puts showcase.entries
> #should this really work ?
> showcase.entries[1]="foo"
> #it does, but looks wrong
> puts showcase.entries
> ----------------------------------

This is a common misunderstanding of references.  I don't know ruby that
well, but if I understand it correctly, it handles references similarly to
many other modern, pointerless OO languages, such as Java and C#.

When you declare @entries, you're declaring a reference to an instance of
an array.  @entries isn't an array, it's a pointer to an instance of the
array class on the heap.  A reference is just a pointer with slightly
different access semantics.  Under the hood, you have a 32 bit value
(assuming a 32 bit platform) that is the heap address of the instance of
the class.  When you write "@entries[0]" what you're really doing is this:

1. Get the heap address of the object from @entries
2. Using that address, find the beginning of the instance on the heap.
3. Read through the instance's structure looking for the address of the
method to call (in this case the indexer - or is it enumerator in ruby?).
4. Call the method of the instance, passing 0 as the argument.
5. Receive the result.

The accessor created by the statement "attr_reader :entries" doesn't
return an array, it returns the reference stored in @entries.  The
reference itself can't be changed (it will always reference the same
instance), but you can call methods of the instance and they can change
the instance's state (including internal data).

The key is to understand that the value stored in @entries is not the
actual array, so the fact that the accessor is read-only doesn't affect
the array itself, only the reference to it.

Weak analogy: Your friend Bob moves into an apartment in an area that has
the zip code (postal code) of 10001.  You write his address down in your
address book in ink because Bob plans to live in that apartment forever. 
Then the Post Office decides to reallocate zip codes and his is changed to
10002.  Your record of his address (a reference) hasn't changed, but the
actual address has.

If you're not familiar with pointers, spend some time studying a language
that has them, such as C.  This can be a hard concept to grasp, but once
you do it makes understanding what's going on under the hood a lot easier,
even in languages that don't expose pointers to the programmer in their
raw form.

-- 
Charles Calvert             |  Software Design/Development
Celtic Wolf, Inc.           |  Project Management
http://www.celticwolf.com/  |  Technical Writing
(703) 580-0210              |  Research