Saturday 24 April 2010

Operator Overloading

Ruby permits operator overloading, allowing you to define how operators will work with your own (or indeed any) classes. Here is a quick example, showing how to define the addition operator. Note that you get the += for free.
class Tester1
def initialize x
@x = x
end

def +(y)
@x + y
end
end

a = Tester1.new 5
puts(a + 3)
# => 8
a += 7
puts a
# => 12

The definition is not commutative, i.e., trying to do 3 + a would fail. To get that to work you would need to override the addition method in Integer - and I think that would be a bad idea.

The next example shows how to override comparison operators. Note that by overriding the equality operator, you get the inequality operator for free. Also note that you are not restricted to returning a boolean; in this example <= returns a string.
class Tester2
def initialize ary
@ary = ary
end

attr_reader :ary

def ==(y)
@ary.length == y.ary.length
end

def <(y)
@ary.length < y.ary.length
end
def <=(y)
'@ary.length < y.ary.length'
end
end

b = Tester2.new %w(zero one two three)
puts b == Tester2.new([1, 2, 3, 4, 5])
# => false
puts b != Tester2.new([1, 2, 3, 4, 5])
# => true
puts b < Tester2.new([1, 2, 3, 4, 5])
# => true
puts b <= Tester2.new([1, 2, 3, 4, 5])
# => "@ary.length < y.ary.length"

You need to be careful when overriding operators, as it has the potential to make your code unfathomable. One time I think it is particular useful, however, is to add array-like properties to a class, for example to access an underlying array, as in this example. Note how the += operator has to be defined via the + operator. Also, the index operator needs two methods if you want to be able to both read from and write to it.
class Tester3
def initialize ary
@ary = ary
end

def [](y)
@ary[y]
end

def []=(y, value)
@ary[y] = value
end

def <<(y)
@ary << y
end

def +(y)
@ary << y
end
end

c = Tester3.new %w(zero one two three)
puts c[3]
# => three
c << 'four'
puts c[4]
# => four
c += 'five'
puts c[5]
# => five

As an aside, be aware that << and += are not the same for an Array object (though they are for Tester3). The += operator requires an array, the members of which are added to the existing array. The << operator appends the new object to the array; if the new object is an array, you have the new array nested inside the existing array.

You cannot override keywords, such as "or", nor can you override:
&& & || | () {} :: . ~ .. ...



Struggling with Ruby: Contents Page

1 comment:

Unknown said...

thanks for this wonderful information.