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 ?
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]
.