Fake Operators and Equality
In Ruby, most operators are actually methods:
1 + 3
# is actually...
1.+(3)
4 == 4
# is actually...
4.==(4)
This is true for the operators bellow:
Operators | Description |
---|---|
`[]`, `[]=` | Collection element getter/setter |
`**` | Exponential operator |
`!`, `~`, `+`, `-` | Not, complement, unary plus and minus |
`*`, `/`, `%` | Multiply, divide, and modulo |
`+`, `-` | Plus, minus |
`>>`, `<<` | Right and left shift |
`&` | Bitwise "and" |
`^`, `|` | Bitwise exclusive and inclusive "or" |
`<=`, `<`, `>`, `>=` | Less than/equal to, etc |
`<=>`, `==`, `===`, `!=`, `=~`, `!~` | Equality and pattern matching |
Operators that are, in fact, methods, can be defined in custom classes1 to change their default behaviors. For example we could compare two Person
classes by their age. To do that, we could use the greater than operator (>
) between two instances:
class Person
def initialize(age)
@age = age
end
def >(other_person)
age > other_person.age
end
def ==(other_person)
age == other_person.age
end
protected
attr_reader :age
end
arthur = Person.new(44)
tommy = Person.new(43)
arthur > tommy # => true
arthur == tommy # => false
(Note the use of protected
which is perfect for this use case.)
Now, defining ==
method gives us !=
. This is not true for >
though.
arthur != tommy # => true
arthur < tommy # => NoMethodError (undefined method `<' for...
If we know we are going to use a lot of comparison, we can include the Comparable
module to our class and define <=>
. By doing this, we are effectively defining all comparison methods.
class Person
include Comparable
def initialize(age)
@age = age
end
def <=>(other_person)
age <=> other_person.age
end
protected
attr_reader :age
end
arthur = Person.new(44)
tommy = Person.new(43)
arthur > tommy # => true
arthur < tommy # => false
arthur == tommy # => false
For the sake of completeness, let’s add that there are also operators which are not methods (and thus, can’t be defined):
Operators | Description |
---|---|
`.`, `::` | Method/constant resolution operators |
`&&` | Logical "and" |
`||` | Logical "or" |
`..`, `...` | Inclusive range, exclusive range |
`?` `:` | Ternary if-then-else |
`=`, `%=`, `/=`, `-=`, `+=`, `|=`, `&=`, `>>=`, `<<=`, `*=`, `&&=`, `||=`, `**=`, `{` | Assignment/shortcuts, block delimiter |
They can also be re-defined for default class. This is called Monkey Patching and is very dangerous, and thus, should be avoided for the time being.
↩︎