[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Unexpected behavior with multidimensional arrays

Armin Armbruster

7/31/2007 3:18:00 PM

Hi,

I need a 3-dim array. The following attempt shows some unexpected
results:

irb(main):001:0> a = Array.new(3)
=> [nil, nil, nil]
irb(main):002:0> a.map!{Array.new(3,[])}
=> [[[], [], []], [[], [], []], [[], [], []]]
irb(main):003:0> a[1][1] << 3.0
=> [3.0]
irb(main):004:0> a
=> [[[], [], []], [[3.0], [3.0], [3.0]], [[], [], []]]

(my expectation would be:
[[[], [], []], [[], [3.0], []], [[], [], []]]
)


After some searching in the forum I found another method:
irb(main):007:0* b = Array.new(3) {Array.new(3,[])}
=> [[[], [], []], [[], [], []], [[], [], []]]
irb(main):008:0> b[1][1] << 3.0
=> [3.0]
irb(main):009:0> b
=> [[[], [], []], [[3.0], [3.0], [3.0]], [[], [], []]]

again, not the expected behavior.

However:
irb(main):016:0> c = Array.new(3) {Array.new(3) {[]}}
=> [[[], [], []], [[], [], []], [[], [], []]]
irb(main):017:0> c[1][1] << 3.0
=> [3.0]
irb(main):018:0> c
=> [[[], [], []], [[], [3.0], []], [[], [], []]]

gives me what I want.

Could anybody please explain to me why my expectations are wrong in the
first two cases?

Thanks,
Armin
--
Posted via http://www.ruby-....

14 Answers

Tim Pease

7/31/2007 5:50:00 PM

0

On 7/31/07, Armin Armbruster <aarmbruster@ndigital.com> wrote:
> Hi,
>
> I need a 3-dim array. The following attempt shows some unexpected
> results:
>
> Could anybody please explain to me why my expectations are wrong in the
> first two cases?
>

This is a very good question -- a classic in the ruby-talk archives.

If you do a search through the ruby-talk archives, you will find some
very enlightening answers. Please post back the thread number that was
most informative for you (just to help others who will ask this same
question again in the future).

Also, read the documentation for Array.new until you grok what it is
saying. Meditate until enlightenment is achieved.

Blessings,
TwP

Armin Armbruster

7/31/2007 6:23:00 PM

0

Tim Pease wrote:
> This is a very good question -- a classic in the ruby-talk archives.
>
> If you do a search through the ruby-talk archives, you will find some
> very enlightening answers. Please post back the thread number that was
> most informative for you (just to help others who will ask this same
> question again in the future).
>
> Also, read the documentation for Array.new until you grok what it is
> saying. Meditate until enlightenment is achieved.
>
> Blessings,
> TwP

Thanks Tim,

I found (among others)
http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-talk/99825?99...

Also, I read the documentation for Array.new again. In fact, I was
reading it before posting, but I guess the human brain (or at least
mine) is pre-conditioned to read what it "believes".

Frankly, just as the poster in ruby-talk I have my troubles accepting
this not being a violation of the principle of least surprise (and yes,
I come from a C programming background).
Anyhow, now I know it and (hopefully) will remember it the next time. I
still have not glue why one would want an array whose elements are
referencing the same object. Does anybody know an example where this is
actually useful?

Armin
--
Posted via http://www.ruby-....

Alex Young

7/31/2007 6:35:00 PM

0

Armin Armbruster wrote:
<snip>
> Anyhow, now I know it and (hopefully) will remember it the next time. I
> still have not glue why one would want an array whose elements are
> referencing the same object. Does anybody know an example where this is
> actually useful?
If it's the object is an immediate (like a Fixnum, or a symbol) you
don't have this problem.

--
Alex

Tim Pease

7/31/2007 6:41:00 PM

0

On 7/31/07, Armin Armbruster <aarmbruster@ndigital.com> wrote:
>
> Frankly, just as the poster in ruby-talk I have my troubles accepting
> this not being a violation of the principle of least surprise (and yes,
> I come from a C programming background).
> Anyhow, now I know it and (hopefully) will remember it the next time. I
> still have not glue why one would want an array whose elements are
> referencing the same object. Does anybody know an example where this is
> actually useful?
>

In ruby, constructing an array and adding the same object multiple
times is the least surprising behavior. Creating several copies of the
object would be "hidden behavior" inside the array initializer, and
hidden behavior is usually a bad thing.

The hidden behavior would force all objects to have valid dup/clone
methods (which is not the case for Fixnum).

As an example consider creating an array of classes using some default
class. The problem here is that we now have several clones of the
default class that are independent of the original. Adding new methods
to the default class is not reflected in the clones.

The current implementation of Array allows the user to choose how
objects are populated in the array. The user can explicitly use the
same object, or the user can create duplicates or new objects per
index using the block format of the initializer. Each form is explicit
which is why the implementation adheres the principle of least
surprise.

Blessings,
TwP

Dan Zwell

7/31/2007 7:15:00 PM

0

Tim Pease wrote:
> On 7/31/07, Armin Armbruster <aarmbruster@ndigital.com> wrote:
>> Frankly, just as the poster in ruby-talk I have my troubles accepting
>> this not being a violation of the principle of least surprise (and yes,
>> I come from a C programming background).
>> Anyhow, now I know it and (hopefully) will remember it the next time. I
>> still have not glue why one would want an array whose elements are
>> referencing the same object. Does anybody know an example where this is
>> actually useful?
>>
>
> In ruby, constructing an array and adding the same object multiple
> times is the least surprising behavior. Creating several copies of the
> object would be "hidden behavior" inside the array initializer, and
> hidden behavior is usually a bad thing.
>

I agree with you on this point. However, I can't think of a situation
where the second argument is useful. For example,
ary = Array.new(n, 0)
can be replaced with
ary = Array.new(n) {0}

So I ask, is this functionality (creating an array with 2 arguments)
useful to people? Because I think everybody makes this mistake once, and
that certainly seems to qualify as being counter-intuitive.

In fact, anything that in done with Array.new(n, obj) can be done with
Array.new(n) {obj}. Am I mistaken? See the following:
>> inner = []
=> []
>> ary = Array.new(3) {inner}
=> [[], [], []]
>> inner << "hi"
=> ["hi"]
>> ary
=> [["hi"], ["hi"], ["hi"]]

The above does the same thing as ary = Array.new(3, []), but needs one
more line of code.

What does everyone think?

Dan

Armin Armbruster

7/31/2007 7:43:00 PM

0

Dan Zwell wrote:
>
> The above does the same thing as ary = Array.new(3, []), but needs one
> more line of code.
>
> What does everyone think?
>
> Dan

Hmm,

I guess my brain is still too much C-wired, but as Dan mentioned so are
the brains of many others. Looks like a pretty frequent mistake to me.
I can't think of a real world example where the current implementation
of Array.new(3,[]) is usefull, but then I don't use arrays of Classes.
It's like in C having an array of pointers that all point to the same
address.

To use Dan's example, if you continue with

irb(main):005:0> ary[1] << "by"
=> ["hi", "by"]
irb(main):006:0> ary
=> [["hi", "by"], ["hi", "by"], ["hi", "by"]]

but obviously that's not what I intended to do (and we already discussed
the solution how to do it right).

Again, if anybody can come up with a simple and halfway applied example
in which the current behavior is useful I would appreciate the
enlightenment very much.

Thanks,
Armin
--
Posted via http://www.ruby-....

Dan Zwell

8/1/2007 12:23:00 AM

0

What would you guys think about removing the second parameter from
Array.new ? I suggest this for 2 reasons:

If the object is a pass-by-copy class such as
Array.new(n, true), or Array.new(n, 23)
then this syntax is exactly the same as
Array.new(n) {true}, or Array.new(n) {23}

If the object is a pass-by-reference, such as
Array.new(n, Klass.new)
this can be represented by
k=Klass.new
Array(n) {k}
This syntax is less pretty, but does anybody even Array.new this way?
It's a sort of nice piece of syntactic sugar, but I don't see how it's
actually useful. Please correct me if I'm wrong about this.

If all of the above is true, I would suggest removing the second
parameter from this method, because it confuses plenty of newcomers.

Thanks,
Dan

Tim Pease

8/1/2007 2:09:00 PM

0

On 7/31/07, Dan Zwell <dzwell@gmail.com> wrote:
>
> If all of the above is true, I would suggest removing the second
> parameter from this method, because it confuses plenty of newcomers.
>

Submit an RCR => http://rcr...

TwP

Kaldrenon

8/1/2007 2:48:00 PM

0

On Jul 31, 8:23 pm, Dan Zwell <dzw...@gmail.com> wrote:
> If all of the above is true, I would suggest removing the second
> parameter from this method, because it confuses plenty of newcomers.

Anecdotal evidence doesn't exactly merit a real rebuttal, but I found
the optional second parameter very intuitive and helpful. In Java I
hated having to write a for loop every time I wanted to initialize the
elements in an array, even when I wanted them to all have the same
contents, and I really like that I can just use one argument in Ruby.

So I agree with you that it's not necessary, but I say don't get rid
of something that's good just because there are other ways to do it.
If all methods are equally valid and easy to understand (as I consider
them to be in this case) then leaving in variety makes it more fun.

-$0.02
Regards,
Andrew

David A. Black

8/1/2007 3:11:00 PM

0