Operator Overloading
In Ruby, operators like +, -, ==, <<, and [] are not special syntax handled by the interpreter — they are ordinary method calls with convenient syntactic sugar. Writing a + b is equivalent to writing a.+(b). Because of this, you can define these methods on your own classes to give custom objects natural, expressive behavior, a technique called operator overloading. This lets domain objects like Money, Vector, or Point support arithmetic and comparison the way built-in numeric types do.
Cricket analogy: When Virat Kohli's bat meets the ball, the umpire doesn't invent a new rule each time — the collision is just a defined action, the same way a + b is really a.+(b) calling a normal method, letting a custom Score class add runs naturally.
Defining arithmetic and comparison operators
To overload an operator, define a method whose name is the operator symbol, accepting one argument (the right-hand operand) for binary operators. Ruby permits overloading most operators except a handful of structural ones like =, .., &&, ||, and not, which remain fixed language constructs.
Cricket analogy: You can coach a batter to sweep, drive, or cut, but you can't redefine what 'out' fundamentally means; likewise Ruby lets you overload most operator methods but keeps structural ones like = and && fixed language rules.
class Vector
attr_reader :x, :y
def initialize(x, y)
@x, @y = x, y
end
def +(other)
Vector.new(x + other.x, y + other.y)
end
def ==(other)
other.is_a?(Vector) && x == other.x && y == other.y
end
def to_s
"(#{x}, #{y})"
end
end
v1 = Vector.new(1, 2)
v2 = Vector.new(3, 4)
puts v1 + v2 #=> (4, 6)
puts v1 == Vector.new(1, 2) #=> trueUnary, indexing, and comparison operators
Unary operators like -@ (negation) and +@ (unary plus) use the @ suffix in their method name to distinguish them from binary versions. Indexing is implemented via [] and []=, and the spaceship operator <=> returns -1, 0, or 1 and is the single method needed to gain full ordering support when combined with the Comparable module.
Cricket analogy: Distinguishing a batter's forward defensive from an aggressive drive needs a clear label; Ruby uses -@ and +@ suffixes to separate unary negation from addition, and <=> lets a Score class gain full ordering via Comparable.
class Vector
# ...
def -@
Vector.new(-x, -y)
end
def [](index)
index.zero? ? x : y
end
end
v = Vector.new(5, -3)
puts(-v) #=> (-5, 3)
puts v[0] #=> 5Python calls this same feature 'dunder methods' (__add__, __eq__, __lt__), and JavaScript has no equivalent — you cannot overload + for custom objects at all in vanilla JS. Ruby's approach is arguably the most direct: the operator literally is the method name, with no special double-underscore naming convention.
Overloading == without also overloading hash and eql? can produce surprising behavior when your objects are used as Hash keys or in a Set, since those data structures rely on hash/eql?, not ==, for lookups. Also, overloading operators to do something unexpected (e.g. making + delete data) violates the principle of least surprise and should be avoided.
- Ruby operators are syntactic sugar for method calls, e.g.
a + bisa.+(b). - Define a method named after the operator symbol to overload it on a custom class.
- Unary operators use an
@suffix in the method name, e.g.-@for unary minus. []and[]=implement custom indexing behavior.<=>combined with the Comparable module provides full ordering with minimal code.- Always keep overloaded operators' behavior intuitive and consistent with their conventional meaning.
Practice what you learned
1. What does the expression `a + b` actually call under the hood in Ruby?
2. How do you define a unary minus operator (e.g. for `-vector`) distinct from binary subtraction?
3. Which single method, combined with the Comparable module, provides `<`, `>`, `==`, `between?`, and `clamp` for free?
4. What is a risk of overloading `==` on a custom class without also defining `hash` and `eql?`?
5. Which of these operators can Ruby developers NOT overload on a custom class?
Was this page helpful?
You May Also Like
Comparable and Enumerable Modules
See how Ruby's Comparable and Enumerable modules let a class gain dozens of methods for free by implementing just one core method each: `<=>` or `each`.
Classes and Objects in Ruby
Learn how Ruby defines classes as blueprints for objects, covering the `class` keyword, `initialize`, instance methods, and how everything in Ruby is an object.
Method Visibility
Learn how Ruby's public, private, and protected keywords control which parts of an object's interface callers can access, and why visibility shapes good API design.
Duck Typing in Ruby
Explore Ruby's duck typing philosophy — objects are defined by the methods they respond to, not by their class — and how it shapes idiomatic, flexible Ruby code.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics