# Conditional overriding of operators

**URL:** <https://www.ruby-forum.com/t/conditional-overriding-of-operators/152467>\
**Category:** Ruby\
**Created:** [November 4, 2008, 10:54am UTC](https://www.ruby-forum.com/t/conditional-overriding-of-operators/152467 "2008-11-04T10:54:09Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![daniel304](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/e5b9ba/32.png) [@daniel304](https://www.ruby-forum.com/u/daniel304)\
**Post date:** [November 4, 2008, 10:54am UTC](https://www.ruby-forum.com/t/conditional-overriding-of-operators/152467/1 "2008-11-04T10:54:09Z")

</div>

Hello!

I am trying to replace .+ operator of Numeric class if and only if  
argument (summand) is my own class.

To be more specific: I am writing geometry module in Ruby and need to  
implement vector-number multiplication so that both:

2 \* vector  
vector \* 2

work well.

Therefore I need to replace .+ method of Numeric without spoiling  
arithmetical operations with other classes. It is clear, that in case of  
inheritance we can just write:

class MyNumeric \< Numeric  
def +(object)  
super(object) unless object.kind\_of?(Vector)

```
# vector-number multiplication here...

```

end  
end

But, of course, we need a replacement here. How to implement it?

class Numeric  
def +(vector)  
unless vector.kinf\_of?(Vector)  
# What to write here??!  
end

```
# vector-number multiplication here...

```

end

---

<div class="post-metadata">

**Author:** ![daniel304](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/e5b9ba/32.png) [@daniel304](https://www.ruby-forum.com/u/daniel304)\
**Post date:** [November 4, 2008, 11:20am UTC](https://www.ruby-forum.com/t/conditional-overriding-of-operators/152467/2 "2008-11-04T11:20:40Z")

</div>

On Nov 4, 4:52 am, Daniel V. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> ```
> # vector-number multiplication here...
> 
> ```
> 
> end  
> end
> 
> But, of course, we need a replacement here. How to implement it?

class Numeric  
alias\_method :\_plus, :+  
def +(vector)  
unless vector.kind\_of?(Vector)  
return \_plus(vector)  
end

```
  # vector-number multiplication here...

```

end

But maybe better something like:

class Numeric  
def self.op\_map(op, klass=nil, &block)  
op = op.to\_sym  
@op\_map ||= {}  
@op\_map[op] ||= {}  
return @op\_map[op] unless klass  
return @op\_map[op][klass] unless block  
@op\_map[op][klass] = block  
end

```
alias_method :_plus, :+

def +(operand)
  if procedure = self.class.op_map[:+][operand.class]
    procedure.call(operand)
  else
    _plus(vector)
  end
end

```

end

Numeric.op\_map(:+,Vector) do |operand|  
# … your vector addition here  
end

T.

---

<div class="post-metadata">

**Author:** ![daniel304](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/e5b9ba/32.png) [@daniel304](https://www.ruby-forum.com/u/daniel304)\
**Post date:** [November 4, 2008, 1:15pm UTC](https://www.ruby-forum.com/t/conditional-overriding-of-operators/152467/3 "2008-11-04T13:15:13Z")

</div>

2008/11/4 Daniel V. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> I am trying to replace .+ operator of Numeric class if and only if  
> argument (summand) is my own class.
> 
> To be more specific: I am writing geometry module in Ruby and need to  
> implement vector-number multiplication so that both:
> 
> 2 \* vector  
> vector \* 2
> 
> work well.

Daniel, look at [ruby-talk:98763], for example here:

[http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/98763](http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/98763)

Regards,  
Pit

---

<div class="post-metadata">

**Author:** ![daniel304](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/e5b9ba/32.png) [@daniel304](https://www.ruby-forum.com/u/daniel304)\
**Post date:** [November 4, 2008, 1:46pm UTC](https://www.ruby-forum.com/t/conditional-overriding-of-operators/152467/4 "2008-11-04T13:46:21Z")

</div>

2008/11/4 Daniel V. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> Therefore I need to replace .+ method of Numeric without spoiling  
> arithmetical operations with other classes.

No, you don’t. You need to implement #coerce and #+, #- etc. in  
_your_ class properly (see the link Pit provided for one, albeit not  
very complete example). Basically your coerce is invoked when Fixnum#+  
sees an instance of your class so you are in control what operation is  
finally implemented.

You can find more hits with  
[http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb?key=coerce&cginame=namazu.rb&submit=Search&dbname=ruby-talk&max=50&whence=0](http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb?key=coerce&cginame=namazu.rb&submit=Search&dbname=ruby-talk&max=50&whence=0)

Cheers

robert

---

<div class="post-metadata">

**Author:** ![daniel304](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/e5b9ba/32.png) [@daniel304](https://www.ruby-forum.com/u/daniel304)\
**Post date:** [November 4, 2008, 3:14pm UTC](https://www.ruby-forum.com/t/conditional-overriding-of-operators/152467/5 "2008-11-04T15:14:23Z")

</div>

Thanks, guys! coercing mechanism is really useful. Due to multiplication  
is commutative, I just swapped multiplier in coerce method, so even if  
(2 \* vector) is called, it calls vector.+(2) finally.

def \*(scalar)  
Vector.new(x \* scalar, y \* scalar)  
end

def coerce(scalar)  
[self, scalar]  
end

vector \* 2 # vector._(2) is called  
2 \* vector # 2._(vector), then vector.coerce(2), then vector.\*(2)

Thanks again! 🙂

---

<div class="post-metadata">

**Author:** ![daniel304](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/e5b9ba/32.png) [@daniel304](https://www.ruby-forum.com/u/daniel304)\
**Post date:** [November 4, 2008, 4:48pm UTC](https://www.ruby-forum.com/t/conditional-overriding-of-operators/152467/6 "2008-11-04T16:48:37Z")

</div>

2008/11/4 Daniel V. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> end  
> I am not sure whether this implementation adheres to the contract of  
> #coerce. Normally you need to return the representative of the  
> _other_ instance first:

irb(main):002:0\> 1.coerce 2.0  
=\> [2.0, 1.0]

It may be ok in your case though. Note also, that you do no type  
checking in #\* which you should do in order to properly react on  
values other than scalars. IMHO normally the logic should be “if the  
other instance is not of the same class as self invoke #coerce on it”.

> vector \* 2 # vector._(2) is called  
> 2 \* vector # 2._(vector), then vector.coerce(2), then vector.\*(2)

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![daniel304](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/e5b9ba/32.png) [@daniel304](https://www.ruby-forum.com/u/daniel304)\
**Post date:** [November 4, 2008, 5:29pm UTC](https://www.ruby-forum.com/t/conditional-overriding-of-operators/152467/7 "2008-11-04T17:29:09Z")

</div>

Hi, Robert.

> I am not sure whether this implementation adheres to the contract of  
> #coerce. Normally you need to return the representative of the  
> _other_ instance first:  
> irb(main):002:0\> 1.coerce 2.0  
> =\> [2.0, 1.0]

Swapping is the main point here, we exploit commutativity of  
multiplication. If Numeric can be _converted back_ to your type, you can  
use this approach (actually you mentioned it in one of threads ;)):  
def coerce(x) [self.class.new( x ), self]; end

But Numeric cannot be converted back to Vector. Just look what people do  
in case of subtraction, which is not commutative:  
[http://groups.google.com/group/ruby-talk-google/browse\_thread/thread/aa288902532dcc6c](http://groups.google.com/group/ruby-talk-google/browse_thread/thread/aa288902532dcc6c)  
(note, he uses swapping too)

> Note also, that you do no type checking in #\* which you should do in order to  
> properly react on values other than scalars.  
> I think you a right here, thanks for comment. I relied on the Vector.\*  
> method, where an exception will be raised if numerical components of  
> vector is multiplied by something else than Numeric. But such exception  
> is not descriptive enough, so I decided to include such checking:

```
def coerce(scalar)
  if scalar.is_a?(Numeric)
    [self, scalar]
  else
    raise ArgumentError, "Vector: cannot coerce #{scalar.inspect}"
  end
end

```

---

<div class="post-metadata">

**Author:** ![daniel304](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/e5b9ba/32.png) [@daniel304](https://www.ruby-forum.com/u/daniel304)\
**Post date:** [November 4, 2008, 2:52pm UTC](https://www.ruby-forum.com/t/conditional-overriding-of-operators/152467/8 "2008-11-04T14:52:41Z")

</div>

Daniel V. ha scritto:

> work well.
> 
> Therefore I need to replace .+ method of Numeric without spoiling  
> arithmetical operations with other classes.

Hi Daniel,

take a look at:

[http://www.splatbang.com/rubyquiz/quiz.rhtml?id=179\_Modular\_Arithmetic](http://www.splatbang.com/rubyquiz/quiz.rhtml?id=179_Modular_Arithmetic)

Hope that helps.  
Andrea
