# (Newbie) Override \* on Array

**URL:** <https://rubytalk.org/t/newbie-override-on-array/41160>\
**Category:** ruby-talk\
**Created:** [4 October 2007 10:52 UTC](https://rubytalk.org/t/newbie-override-on-array/41160 "2007-10-04T10:52:48Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![Mike\_Ho](https://avatars.discourse-cdn.com/v4/letter/m/a6a055/32.png) [@Mike\_Ho](https://rubytalk.org/u/Mike_Ho)\
**Post date:** [4 October 2007 10:52 UTC](https://rubytalk.org/t/newbie-override-on-array/41160/1 "2007-10-04T10:52:48Z")

</div>

Hi,

I've written a simplistic override of the \* operator for Arrays so that  
[2,4,6]\*[2,2,2] = [4,8,12]

class Array

&nbsp;&nbsp;def \*(other)

&nbsp;&nbsp;&nbsp;&nbsp;each\_with\_index do |x,i|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self[i]= x \* other[i]  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end

end

It assumes that the arrays are the same length and no error checking is  
done.

My questions are; is this idiomatic Ruby?  
What solution would an experienced Rubyist offer?  
How would it be best to handle exceptions when the arrays are of  
different dimensions and/or length?

Many Thanks

Mike

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/](http://www.ruby-forum.com/).

---

<div class="post-metadata">

**Author:** ![Stefano\_Crocco](https://avatars.discourse-cdn.com/v4/letter/s/5f9b8f/32.png) [@Stefano\_Crocco](https://rubytalk.org/u/Stefano_Crocco)\
**Post date:** [4 October 2007 11:04 UTC](https://rubytalk.org/t/newbie-override-on-array/41160/2 "2007-10-04T11:04:23Z")

</div>

Alle giovedì 4 ottobre 2007, Mike Ho ha scritto:

> Hi,
> 
> I've written a simplistic override of the \* operator for Arrays so that  
> [2,4,6]\*[2,2,2] = [4,8,12]
> 
> class Array
> 
> &nbsp;&nbsp;def \*(other)
> 
> &nbsp;&nbsp;&nbsp;&nbsp;each\_with\_index do |x,i|  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self[i]= x \* other[i]  
> &nbsp;&nbsp;&nbsp;&nbsp;end  
> &nbsp;&nbsp;end
> 
> end
> 
> It assumes that the arrays are the same length and no error checking is  
> done.
> 
> My questions are; is this idiomatic Ruby?  
> What solution would an experienced Rubyist offer?  
> How would it be best to handle exceptions when the arrays are of  
> different dimensions and/or length?
> 
> Many Thanks
> 
> Mike

Usually, operators don't modify the operands, but return a new object with the  
result. For instance:

irb: 001\> a1 = [1, 2 ,3]  
[1, 2, 3]  
irb: 002\> a2 = [4,5]  
[4, 5]  
irb: 003\> a1 + a2  
[1, 2, 3, 4, 5]  
irb: 004\> a1  
[1, 2, 3]  
irb: 005\> a2  
[4, 5]

Your method, instead, modifies the first operand:

a1 = [1,2,3]  
a2= [4,5,6]  
a3 = a1\*a2  
p a1  
=\> [4, 10, 18]  
p a3  
=\> [4, 10, 18]

I'd do it this way:

class Array

&nbsp;&nbsp;def \*(other)  
&nbsp;&nbsp;&nbsp;&nbsp;res =   
&nbsp;&nbsp;&nbsp;&nbsp;each\_with\_index do |x,i|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res[i]= x \* other[i]  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;res  
&nbsp;&nbsp;end

end

or

require 'generator'

class Array

&nbsp;&nbsp;def \*(other)  
&nbsp;&nbsp;&nbsp;&nbsp;SyncEnumerator.new(self, other).map{|x, y| x\*y}  
&nbsp;&nbsp;end

end

Regarding errors, you I think you can check the size of the two array at the  
beginning of the method and raise TypeError if they're different.

I hope this helps

Stefano

---

<div class="post-metadata">

**Author:** ![Robert\_K1](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/robert_k1/32/1830_2.png) [@Robert\_K1](https://rubytalk.org/u/Robert_K1)\
**Post date:** [4 October 2007 11:25 UTC](https://rubytalk.org/t/newbie-override-on-array/41160/3 "2007-10-04T11:25:40Z")

</div>

> Hi,
> 
> I've written a simplistic override of the \* operator for Arrays so that  
> [2,4,6]\*[2,2,2] = [4,8,12]
> 
> class Array
> 
> &nbsp;&nbsp;def \*(other)
> 
> &nbsp;&nbsp;&nbsp;&nbsp;each\_with\_index do |x,i|  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self[i]= x \* other[i]  
> &nbsp;&nbsp;&nbsp;&nbsp;end  
> &nbsp;&nbsp;end
> 
> end
> 
> It assumes that the arrays are the same length and no error checking is  
> done.
> 
> My questions are; is this idiomatic Ruby?

No. (see Stefano's reply)

> What solution would an experienced Rubyist offer?

irb(main):002:0\> require 'enumerator'  
=\> true  
irb(main):003:0\> a1=[1,2,3]  
=\> [1, 2, 3]  
irb(main):004:0\> a2=[4,5,6]  
=\> [4, 5, 6]  
irb(main):005:0\> a3=a1.to\_enum(:zip, a2).map {|x,y| x\*y}  
=\> [4, 10, 18]

> How would it be best to handle exceptions when the arrays are of  
> different dimensions and/or length?

If the second array is shorter, you get automatic checking:

irb(main):008:0\> (a1+[111]).to\_enum(:zip, a2).map {|x,y| x\*y}  
TypeError: nil can't be coerced into Fixnum  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):10:in `\*'  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):10  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):10:in `map'  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):10:in `each'  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):10:in `zip'  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):10:in `each'  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):10:in `map'  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):10

In the other case the result array just has the length of the first array:

irb(main):009:0\> a1.to\_enum(:zip, a2+[111]).map {|x,y| x\*y}  
=\> [4, 10, 18]

Depends on what you want to do what kind of error checking you need.

Kind regards

robert

> **···**
>
> 2007/10/4, Mike Ho \<mike\_houghton@xyratex.com\>:  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from :0

---

<div class="post-metadata">

**Author:** ![Stefano\_Crocco](https://avatars.discourse-cdn.com/v4/letter/s/5f9b8f/32.png) [@Stefano\_Crocco](https://rubytalk.org/u/Stefano_Crocco)\
**Post date:** [4 October 2007 11:38 UTC](https://rubytalk.org/t/newbie-override-on-array/41160/4 "2007-10-04T11:38:23Z")

</div>

Alle giovedì 4 ottobre 2007, Stefano Crocco ha scritto:

> Regarding errors, you I think you can check the size of the two array at  
> the beginning of the method and raise TypeError if they're different.

Sorry, it should be ArgumentError, not TypeError. Looking at ruby standard  
library, TypeError is used when an object of the wrong type is passed (for  
example, passing an Array to Kernel.Integer), while ArgumentError is used  
when the argument is of the correct type, but doesn't meet some other  
requirements (for example, passing a string which doesn't represent a number  
to Kernel.Integer). In this case, the argument is of the correct type  
(Array), but the requirement "having the same size of the receiver" is not  
met, so I think you should use ArgumentError.

Stefano

---

<div class="post-metadata">

**Author:** ![Mike\_Ho](https://avatars.discourse-cdn.com/v4/letter/m/a6a055/32.png) [@Mike\_Ho](https://rubytalk.org/u/Mike_Ho)\
**Post date:** [4 October 2007 12:51 UTC](https://rubytalk.org/t/newbie-override-on-array/41160/5 "2007-10-04T12:51:40Z")

</div>

Stefano Crocco wrote:

> require 'generator'
> 
> class Array
> 
> &nbsp;&nbsp;def \*(other)  
> &nbsp;&nbsp;&nbsp;&nbsp;SyncEnumerator.new(self, other).map{|x, y| x\*y}  
> &nbsp;&nbsp;end
> 
> end
> 
> Regarding errors, you I think you can check the size of the two array at  
> the  
> beginning of the method and raise TypeError if they're different.
> 
> I hope this helps
> 
> Stefano

Thanks for the replies guys.

The SyncEnumerator looks elegant but when I tried it I got the following  
error

in `*': undefined method `\*' for nil:NilClass (NoMethodError)

for the line

SyncEnumerator.new(self, other).map{|x, y| x\*y}

I call the method by...

a1=[2, 4, 6]  
a2= [2, 2, 2]

puts a1\*a2

I put some debug in like this

def \*(other)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SyncEnumerator.new(self, other).map do |x,y|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts "x #{x} y #{y}"  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x\*y  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end

and the output I get is this  
x 2 y 2  
x 4 y 2  
x 6 y 2  
x y  
C:/ruby\_work/test/scratch.rb:23:in `*': undefined method `\*' for  
nil:NilClass (NoMethodError)  
So it seems to 'run off the end'

Any thoughts ?

Thanks

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Forum](https://avatars.discourse-cdn.com/v4/letter/f/43a26b/32.png) [@Forum](https://rubytalk.org/u/Forum)\
**Post date:** [4 October 2007 13:32 UTC](https://rubytalk.org/t/newbie-override-on-array/41160/6 "2007-10-04T13:32:44Z")

</div>

#\<\< being an exception, are there others?

But the important thing is that #\* does not and you would need some  
very good reason to break this behavior.  
I am however much more pragmatic about the second part , personally I  
would expect  
Array#\* an\_array to deliver the carthesian product, that all said in  
your case I'd just throw an exception if the arrays' sizes do not  
match.

Cheers  
Robert

> **···**
>
> On 10/4/07, Stefano Crocco \<stefano.crocco@alice.it\> wrote:
> 
> > Alle giovedì 4 ottobre 2007, Mike Ho ha scritto:  
> > \> Hi,  
> > \>  
> > \> I've written a simplistic override of the \* operator for Arrays so that  
> > \> [2,4,6]\*[2,2,2] = [4,8,12]  
> > \>  
> > \> class Array  
> > \>  
> > \> def \*(other)  
> > \>  
> > \> each\_with\_index do |x,i|  
> > \> self[i]= x \* other[i]  
> > \> end  
> > \> end  
> > \>  
> > \> end  
> > \>  
> > \> It assumes that the arrays are the same length and no error checking is  
> > \> done.  
> > \>  
> > \> My questions are; is this idiomatic Ruby?  
> > \> What solution would an experienced Rubyist offer?  
> > \> How would it be best to handle exceptions when the arrays are of  
> > \> different dimensions and/or length?  
> > \>  
> > \>  
> > \> Many Thanks  
> > \>  
> > \> Mike
> > 
> > Usually, operators don't modify the operands, but return a new object with the  
> > result.
> 
> --  
> what do I think about Ruby?  
> [http://ruby-smalltalk.blogspot.com/](http://ruby-smalltalk.blogspot.com/)

---

<div class="post-metadata">

**Author:** ![Brian\_Adkins](https://avatars.discourse-cdn.com/v4/letter/b/3ab097/32.png) [@Brian\_Adkins](https://rubytalk.org/u/Brian_Adkins)\
**Post date:** [5 October 2007 17:30 UTC](https://rubytalk.org/t/newbie-override-on-array/41160/7 "2007-10-05T17:30:04Z")

</div>

Thanks for the tip on SyncEnumerator.

If a class/module must be opened, I think Enumerator would be better  
than Array. Also, I prefer method names over operators in this case,  
but that's a personal preference:

require 'generator'  
require 'pp'

module Enumerable  
&nbsp;&nbsp;def cartesian\_product other  
&nbsp;&nbsp;&nbsp;&nbsp;self.inject() {|result, a| other.each {|b| result \<\< [a, b] };  
result }  
&nbsp;&nbsp;end

&nbsp;&nbsp;def dot\_product other  
&nbsp;&nbsp;&nbsp;&nbsp;SyncEnumerator.new(self, other).inject(0) {|s,v| s += v[0]\*v[1];  
s }  
&nbsp;&nbsp;end

&nbsp;&nbsp;def mmap \*others, &f  
&nbsp;&nbsp;&nbsp;&nbsp;SyncEnumerator.new(self, \*others).map(&f)  
&nbsp;&nbsp;end

&nbsp;&nbsp;def cross\_product other  
&nbsp;&nbsp;&nbsp;&nbsp;# exercise for reader  
&nbsp;&nbsp;end  
end

x = [1, 2, 3]  
y = [1, 10, 100]

pp x.dot\_product(y)  
puts '-'\*10  
pp x.mmap(y) {|a,b| a\*b }  
pp x.mmap(y, [1, 2, 4]) {|a,b,c| a\*b\*c }  
puts '-'\*10  
pp x.cartesian\_product(y)  
puts '-'\*10

BTW, with the mmap call above, I originally got bit by a scope issue  
because I named the local variables |x,y|, so the assignment to the  
block variables overwrote x & y in the outer scope ☹

Personally, I'd prefer to not open a class/module and simply define  
functions.

def cartesian\_product enum1, enum2  
&nbsp;&nbsp;enum1.inject() {|result, a| enum2.each {|b| result \<\< [a, b] };  
result }  
end

def dot\_product enum1, enum2  
&nbsp;&nbsp;SyncEnumerator.new(enum1, enum2).inject(0) {|s,v| s += v[0]\*v[1];  
s }  
end

def mmap \*enums, &f  
&nbsp;&nbsp;SyncEnumerator.new(\*enums).map(&f)  
end

pp dot\_product(x, y)  
puts '-'\*10  
pp mmap(x, y) {|a,b| a\*b }  
pp mmap(x, y, [1, 2, 4]) {|a,b,c| a\*b\*c }  
puts '-'\*10  
pp cartesian\_product(x, y)

> **···**
>
> On Oct 4, 7:04 am, Stefano Crocco \<stefano.cro...@alice.it\> wrote:
> 
> > require 'generator'
> > 
> > class Array
> > 
> > &nbsp;&nbsp;def \*(other)  
> > &nbsp;&nbsp;&nbsp;&nbsp;SyncEnumerator.new(self, other).map{|x, y| x\*y}  
> > &nbsp;&nbsp;end
> > 
> > end

---

<div class="post-metadata">

**Author:** ![James\_Britt](https://avatars.discourse-cdn.com/v4/letter/j/22d042/32.png) [@James\_Britt](https://rubytalk.org/u/James_Britt)\
**Post date:** [4 October 2007 13:09 UTC](https://rubytalk.org/t/newbie-override-on-array/41160/8 "2007-10-04T13:09:04Z")

</div>

some things probably shouldn't be overridden.  
it's not C++  
but try getting similar functionality with a function or method approach...

> **···**
>
> On Oct 4, 2007, at 7:51 AM, Mike Ho wrote:
> 
> > Stefano Crocco wrote:
> > 
> > > require 'generator'
> > > 
> > > class Array
> > > 
> > > &nbsp;&nbsp;def \*(other)  
> > > &nbsp;&nbsp;&nbsp;&nbsp;SyncEnumerator.new(self, other).map{|x, y| x\*y}  
> > > &nbsp;&nbsp;end
> > > 
> > > end
> > > 
> > > Regarding errors, you I think you can check the size of the two array at  
> > > the  
> > > beginning of the method and raise TypeError if they're different.
> > > 
> > > I hope this helps
> > > 
> > > Stefano
> > 
> > Thanks for the replies guys.
> > 
> > The SyncEnumerator looks elegant but when I tried it I got the following  
> > error
> > 
> > in `*': undefined method `\*' for nil:NilClass (NoMethodError)
> > 
> > for the line
> > 
> > SyncEnumerator.new(self, other).map{|x, y| x\*y}
> > 
> > I call the method by...
> > 
> > a1=[2, 4, 6]  
> > a2= [2, 2, 2]
> > 
> > puts a1\*a2
> > 
> > I put some debug in like this
> > 
> > def \*(other)  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SyncEnumerator.new(self, other).map do |x,y|  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts "x #{x} y #{y}"  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x\*y  
> > &nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;end
> > 
> > and the output I get is this  
> > x 2 y 2  
> > x 4 y 2  
> > x 6 y 2  
> > x y  
> > C:/ruby\_work/test/scratch.rb:23:in `*': undefined method `\*' for  
> > nil:NilClass (NoMethodError)  
> > So it seems to 'run off the end'
> > 
> > Any thoughts ?
> > 
> > Thanks
> > 
> > --  
> > Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Stefano\_Crocco](https://avatars.discourse-cdn.com/v4/letter/s/5f9b8f/32.png) [@Stefano\_Crocco](https://rubytalk.org/u/Stefano_Crocco)\
**Post date:** [4 October 2007 18:32 UTC](https://rubytalk.org/t/newbie-override-on-array/41160/9 "2007-10-04T18:32:40Z")

</div>

Alle giovedì 4 ottobre 2007, Mike Ho ha scritto:

> Stefano Crocco wrote:  
> \> require 'generator'  
> \>  
> \> class Array  
> \>  
> \> def \*(other)  
> \> SyncEnumerator.new(self, other).map{|x, y| x\*y}  
> \> end  
> \>  
> \> end  
> \>  
> \> Regarding errors, you I think you can check the size of the two array at  
> \> the  
> \> beginning of the method and raise TypeError if they're different.  
> \>  
> \> I hope this helps  
> \>  
> \> Stefano
> 
> Thanks for the replies guys.
> 
> The SyncEnumerator looks elegant but when I tried it I got the following  
> error
> 
> in `*': undefined method `\*' for nil:NilClass (NoMethodError)
> 
> for the line
> 
> SyncEnumerator.new(self, other).map{|x, y| x\*y}
> 
> I call the method by...
> 
> a1=[2, 4, 6]  
> a2= [2, 2, 2]
> 
> puts a1\*a2
> 
> I put some debug in like this
> 
> def \*(other)  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SyncEnumerator.new(self, other).map do |x,y|  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts "x #{x} y #{y}"  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x\*y  
> &nbsp;&nbsp;&nbsp;&nbsp;end  
> &nbsp;&nbsp;end
> 
> and the output I get is this  
> x 2 y 2  
> x 4 y 2  
> x 6 y 2  
> x y  
> C:/ruby\_work/test/scratch.rb:23:in `*': undefined method `\*' for  
> nil:NilClass (NoMethodError)  
> So it seems to 'run off the end'
> 
> Any thoughts ?
> 
> Thanks

This is strange. It works correctly for me:

require 'generator'

class Array

&nbsp;&nbsp;def \*(other)  
&nbsp;&nbsp;&nbsp;&nbsp;SyncEnumerator.new(self, other).map{|x, y| x\*y}  
&nbsp;&nbsp;end

end

a1 = [2,4,6]  
a2 = [2,2,2]  
puts a1\*a2  
=\> 4  
&nbsp;&nbsp;&nbsp;8  
&nbsp;&nbsp;&nbsp;12

I can't understand why it isn't working for you.

Stefano

---

<div class="post-metadata">

**Author:** ![Mike\_Ho](https://avatars.discourse-cdn.com/v4/letter/m/a6a055/32.png) [@Mike\_Ho](https://rubytalk.org/u/Mike_Ho)\
**Post date:** [5 October 2007 08:53 UTC](https://rubytalk.org/t/newbie-override-on-array/41160/10 "2007-10-05T08:53:53Z")

</div>

Stefano Crocco wrote:

> I can't understand why it isn't working for you.
> 
> Stefano

Ooops! It does work, I was also extending Fixnum and hacking ops in  
there!

Again the SyncEnumerator is elegant especially combined with the map{}

Thanks

Mike

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).
