Search code examples
rubyarraysoperatorscoercion

ruby coerce method not called as expected


My aim is to implement an addition operator for a mathematical vector. I need ability to add scalars, arrays to MyVector. Also i need the operation to be commutative so i can add numbers to MyVector, and MyVector to number. I followed the recipe here In Ruby, how does coerce() actually work? and a few other internet resources to define the following + operator.

class MyVector
    def initialize(x,y,z)
      @x, @y, @z = x, y, z
    end
    def +(other)
      case other
      when Numeric
        MyVector.new(@x + other, @y + other, @z + other)
      when Array
        MyVector.new(@x + other[0], @y + other[1], @z + other[2])
      end
    end
    def coerce(other)
      p "coercing #{other.class}"
      [self, other]
    end
end

t = MyVector.new(0, 0, 1)

p t + 1
p 1 + t

p t + [3 , 4 , 5]
p [3 , 4 , 5] + t

and the output is

#<MyVector:0x007fd3f987d0a0 @x=1, @y=1, @z=2>
"coercing Fixnum"
#<MyVector:0x007fd3f987cd80 @x=1, @y=1, @z=2>
#<MyVector:0x007fd3f987cbf0 @x=3, @y=4, @z=6>
test.rb:26:in `<main>': no implicit conversion of MyVector into Array (TypeError)

Clearly coerce is doing its job when adding numbers but doesn't seem to work for Arrays. Instead the + method on the Array class seems to get called and it tries to convert MyVector to Array, which fails. My question is, why does the coerce method for MyVector not get called ?


Solution

  • coerce does coercions for numeric types. An Array is not a numeric type. Array#+ is not addition, it is concatenation, it behaves differently from numeric addition, e.g. [1, 2, 3] + [4, 5, 6] is not the same as [4, 5, 6] + [1, 2, 3].