Ruby Operator Overloading Question

Ruby operator overloading

I believe the answer to "ruby operator overloading question" addresses both your points by using is_a? and coerce.

With regards to your first point. The normal approach in Ruby is to use respond_to? where possible, rather than checking for type. If for some reason you specifically need to check for type, then using is_a? is the correct way.

ruby operator overloading question

Using coerce is a MUCH better approach than monkey-patching a core class:

class Vec3
attr_accessor :x,:y,:z

def *(a)
if a.is_a?(Numeric) #multiply by scalar
return Vec3.new(@x*a, @y*a, @z*a)
elsif a.is_a?(Vec3) #dot product
return @x*a.x + @y*a.y + @z*a.z
end
end

def coerce(other)
return self, other
end
end

if you define v as v = Vec3.new then the following will work: v * 5 and 5 * v
The first element returned by coerce (self) becomes the new receiver for the operation, and the second element (other) becomes the parameter, so 5 * v is exactly equivalent to v * 5

Ruby overload + operator

Overloaded operator is resolved based on the class of the first operand, so if you wanted to overload the addition of simple integers, something like that should work:

class Fixnum
def +(other)
return self * other
end
end

I do not recommend you to actually do this, btw.

list of ruby operators that can be overridden/implemented

Here's a table of the Ruby operators.

The ones that are methods and overloadable are:

[ ] [ ]=    Element reference, element set
** Exponentiation
! ~ + - Not, complement, unary plus and minus (method names for the last two are +@ and -@)
* / % Multiply, divide, and modulo
+ - Plus and minus
>> << Right and left shift
& Bitwise `and'
^ | Bitwise exclusive `or' and regular `or'
<= < > >= Comparison operators
<=> == === != =~ !~ Equality and pattern match operators (!= and !~ may not be defined as methods)

The table was from the 2001 Pickaxe book, but that's the same table as in the Ruby 1.9 Pickaxe book -- no reason to believe that this set of infix operators will ever change.

Ruby method for +=

The += operator is not associated to any method, it is just syntactic sugar, when you write a += b the Ruby interpreter transform it to a = a + b, the same is for a.b += c that is transformed to a.b = a.b + c. Thus you just have to define the methods x= and x as you need:

class Plane 
def initialize
@moved = 0
@x = 0
end

attr_reader :x
def x=(x)
@x = x
@moved += 1
end

def to_s
"moved #{@moved} times, current x is #{@x}"
end

end

plane = Plane.new
plane.x += 5
plane.x += 10
puts plane.to_s
# => moved 2 times, current x is 15

Ruby: overload operator behaviour for some cases only

Both approaches posted here so far are a legacy Rails way, which is plain wrong. It relies on the fact that the class has no method called plus and nobody will reopen the class to create a method called plus. Otherwise things will go mad.

The correct solution is Module#prepend:

Integer.prepend(Module.new do
def + other
case other
when Fixnum then special_behaviour
else super(other)
end
end
end)

question on overriding + operator in ruby

You should not mutate the object when implementing + operator. Instead return a new Point Object:

class Point
attr_accessor :x, :y

def initialize(x,y)
@x, @y = x, y
end

def +(other)
Point.new(@x + other.x, @y + other.y)
end

def to_s
"(#{@x}, #{@y})"
end
end

ruby-1.8.7-p302:
> p1 = Point.new(1,2)
=> #<Point:0x10031f870 @y=2, @x=1>
> p2 = Point.new(3, 4)
=> #<Point:0x1001bb718 @y=4, @x=3>
> p1 + p2
=> #<Point:0x1001a44c8 @y=6, @x=4>
> p3 = p1 + p2
=> #<Point:0x1001911e8 @y=6, @x=4>
> p3
=> #<Point:0x1001911e8 @y=6, @x=4>
> p1 += p2
=> #<Point:0x1001877b0 @y=6, @x=4>
> p1
=> #<Point:0x1001877b0 @y=6, @x=4>

How do you overload the operator in Ruby?

You need to do that from within a class. Like this:

class Whatever
attr_accessor :roles
def initialize
@roles = []
end
end

You can't really have a <<roles method. You'd have to have an accessor for roles that supports the << operator.

EDIT: I've updated the code. Now you can see how the << operator should be overloaded, but you can also do what the roles<< part. Here's a small snippet of it's usage:

w = Whatever.new
w << "overload for object called"
# and overloads for the roles array
w.roles << "first role"
w.roles << "second role"


Related Topics



Leave a reply



Submit