Overriding the == Operator in Ruby

Overriding the == operator in Ruby

In Ruby == is just a method (with some syntax sugar on top allowing you to write foo == bar instead of foo.==(bar)) and you override == just like you would any other method:

class MyClass
def ==(other_object)
# return true if self is equal to other_object, false otherwise
end
end

override the = operator in ruby

Sorry, you can't do this. When you write foo = bar, you're just assigning a variable, not calling any method. It's only something.foo = bar that desugars to a method call, and just like everywhere else, the receiver of that method call is the thing before the dot.

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.

Overriding == equality operator works only in one direction

It's not possible without changing other classes. Basically a == b equals a.==(b). So you need to override == operator for the second class if you want to make it work.

Overload = operator ruby?

Of course you can! It would help to google for Ruby's spaceship operator.

You need to include Comparable module, and then implement the method. Take a look at simple example of overwriting <=>: http://brettu.com/rails-daily-ruby-tips-121-spaceship-operator-example/

I'll take an example from the article:

class Country
include Comparable

attr_accessor :age

def initialize(age)
@age = age
end

def <=>(other_country)
age <=> other_country.age
end
end

For overloading the <=> you don't need to include Comparable module, however by including it, it "mixins" some useful methods to your Country class with which you can perform comparisons.

Let's see some examples:

country1 = Country.new(50)
country2 = Country.new(25)

country1 > country2
# => true

country1 == country2
# => false

country1 < country2
# => false

country3 = Country.new(23)

[country1, country2, country3].sort
# => [country3, country2, country1]

But, if the Comparable module was not included:

country1 > country2
# => NoMethodError: undefined method `>' for #<Country:...>

Good luck!

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)

How do you override the ruby case equality operator? (===)

The expression after the 'case' keyword is the right hand side of the === expression, and the expression after the 'when' keyword is on the left hand side of the expression. So, the method that is being called is String.===, not A.===.

A quick approach to reversing the comparison:

class Revcomp
def initialize(obj)
@obj = obj
end

def ===(other)
other === @obj
end

def self.rev(obj)
Revcomp.new(obj)
end
end

class Test
def ===(other)
puts "here"
end
end

t = Test.new

case t
when Revcomp.rev("abc")
puts "there"
else
puts "somewhere"
end

How can I override the .. and ... operators of Ruby Ranges to accept Float::INFINITY?

I don't think that what you want to do is a correct way of solving such issue.

What I would suggest instead, is to simply override the end_date method in model:

def end_date
super == Float::INFINITY ? DateTime::Infinity.new : super
end

This basically says if end_date in db is Float::INFINITY return DateTime::Infinity.new as end_date, otherwise return what's in database.

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>


Related Topics



Leave a reply



Submit