suprised by destructive map (not map!)

B

Boris Schmid

Occasionally I run into bits of ruby that are surprising to me (although
might not be to matz). Here is one of them. Should I file this as a bug
(I thought .map is supposed to be non-destructive), or just keep in mind
which classes are passed by value and which are passed by reference.

Basically: map (and naturally also map!) is destructive when your array
includes elements which are normally not passed by value but by
reference.

ruby 1.8.6 (2007-09-24 patchlevel 111) [x86_64-linux]
boris:falcon:~:irb

"unexpected (for me)"
irb(main):001:0> array = [[1],[2]]
=> [[1], [2]]
irb(main):002:0> array.map {|i| i << 3}
=> [[1, 3], [2, 3]]
irb(main):003:0> array
=> [[1, 3], [2, 3]]
irb(main):004:0>

"expected behaviour"
irb(main):005:0* array = [1,2]
=> [1, 2]
irb(main):006:0> array.map {|i| i + 3}
=> [4, 5]
irb(main):007:0> array
=> [1, 2]
irb(main):008:0>
 
A

Alex Young

Boris said:
Occasionally I run into bits of ruby that are surprising to me (although
might not be to matz). Here is one of them. Should I file this as a bug
(I thought .map is supposed to be non-destructive), or just keep in mind
which classes are passed by value and which are passed by reference.

Basically: map (and naturally also map!) is destructive when your array
includes elements which are normally not passed by value but by
reference.

ruby 1.8.6 (2007-09-24 patchlevel 111) [x86_64-linux]
boris:falcon:~:irb

"unexpected (for me)"
irb(main):001:0> array = [[1],[2]]
=> [[1], [2]]
irb(main):002:0> array.map {|i| i << 3}
=> [[1, 3], [2, 3]]
irb(main):003:0> array
=> [[1, 3], [2, 3]]
irb(main):004:0>

It's not map that's destructive here, it's the #<< method. Map iterates
over the original array, and creates a new one with the results of the
block - it doesn't copy the original array first.
 
B

Bernardo Monteiro Rufino

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

Use it:
irb(main):001:0> array = [[1], [2]]
=> [[1], [2]]
irb(main):002:0> array.map{|a| a += [3]}
=> [[1, 3], [2, 3]]
irb(main):003:0> array
=> [[1], [2]]
 
A

Alex Young

Bernardo said:
Use it:
irb(main):001:0> array = [[1], [2]]
=> [[1], [2]]
irb(main):002:0> array.map{|a| a += [3]}

That expands to:

array.map{|a| a = a + [3] }

The Array#+ method isn't destructive, and a variable assignment in a
block isn't either.
 
B

Bernardo Monteiro Rufino

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

Exactly
 
B

Boris Schmid

Thanks for clarifying that. I'll compile a list of destructive methods
for myself, and be aware of them when I map.

Also learned not to trust blindly in the ! from another post.
 
R

Robert Klemme

2007/12/13 said:
Thanks for clarifying that. I'll compile a list of destructive methods
for myself, and be aware of them when I map.

Also learned not to trust blindly in the ! from another post.

You should also remember that all parameters are passed by reference*.
Whether hazard occurs depends on what you do with them, especially
the mutable ones. In your case elements in your Array were Arrays
which are mutable. The issue does not happen if you used integers
instead - even with <<:

irb(main):001:0> a1 = [1,2]
=> [1, 2]
irb(main):002:0> a2 = a1.map {|x| x << 1}
=> [2, 4]
irb(main):003:0> a1
=> [1, 2]

* Note: this is not 100% correct implementation wise but describes the
situation properly from a Ruby user's point of view.

Kind regards

robert
 
T

tho_mica_l

irb(main):002:0> array.map {|i| i << 3}
=> [[1, 3], [2, 3]]

Well, Array#<< means: __append__ an element to an array and return
the
array. It does not mean make a copy of the array plus the new
element.
What you expected would be one of

array.map {|i| i.dup << 3}
array.map {|i| i + [3]}

It's not necessary to use += here since the value of "i += [3]" is i,
which you really don't care about since you only want "i + [3]".

Fixnum#<< means shift bits. Same symbol but totally different story.
Also, numerics are no container classes but have immediate values,
i.e.
they are not passed by reference (according to Programming Ruby 2,
p463), which is also why you can't dup/clone them.
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top