Best Practices
Keep operators intuitive.
Best Practices is a free Kotlin Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Kotlin Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Keep Operators Intuitive
Overload an operator only when its meaning is obvious. + on vectors is clear; + meaning send-email is not.
data class Vec(val x: Int, val y: Int) {
operator fun plus(o: Vec) = Vec(x + o.x, y + o.y)
}
fun main() {
println(Vec(1, 2) + Vec(3, 4))
}Preserve Expected Semantics
Honor the usual algebra: a + b should be commutative-feeling for symmetric types and should not surprise readers.
data class Money(val cents: Int) {
operator fun plus(o: Money) = Money(cents + o.cents)
}
fun main() {
println(Money(100) + Money(50))
}Prefer Immutability
Operators like plus should return a new value rather than mutating the receiver, matching how numbers behave.
data class Point(val x: Int) {
operator fun plus(o: Point) = Point(x + o.x)
}
fun main() {
val a = Point(1)
val b = a + Point(2)
println("${a.x} ${b.x}")
}plus vs plusAssign
Define plus for immutable values; define plusAssign for in-place mutation of mutable containers. Avoid defining both with conflicting behavior.
class Cart {
val items = mutableListOf<String>()
operator fun plusAssign(item: String) { items.add(item) }
}
fun main() {
val c = Cart()
c += "book"
println(c.items)
}Match Return Types
Return the same type from binary operators so results chain naturally.
data class N(val v: Int) {
operator fun plus(o: N) = N(v + o.v)
}
fun main() {
println((N(1) + N(2) + N(3)).v)
}Do Not Overload for Cleverness
If a named function reads better, use it. Operators are for genuinely numeric or container-like semantics, not puzzles.
data class Log(val lines: List<String>) {
fun append(line: String) = Log(lines + line)
}
fun main() {
println(Log(emptyList()).append("start").lines)
}Keep equals and hashCode Consistent
If you overload comparison or equality, keep equals and hashCode in sync to avoid broken collections.
data class Id(val v: Int)
fun main() {
val set = hashSetOf(Id(1), Id(1))
println(set.size)
}Watch Operator Precedence
Overloaded operators keep built-in precedence. Design so that natural precedence gives expected results.
data class N(val v: Int) {
operator fun plus(o: N) = N(v + o.v)
operator fun times(o: N) = N(v * o.v)
}
fun main() {
println((N(2) + N(3) * N(4)).v)
}Document Surprising Operators
If an operator does anything non-obvious, add a comment or KDoc so callers are not misled.
data class Range2(val start: Int, val end: Int) {
// contains: is value inside the range?
operator fun contains(v: Int) = v in start..end
}
fun main() {
println(5 in Range2(1, 10))
}Use contains for in
The in operator maps to contains. Override it only when membership is well-defined for your type.
class Team(val members: List<String>) {
operator fun contains(name: String) = name in members
}
fun main() {
val t = Team(listOf("Ann", "Bo"))
println("Ann" in t)
}When in Doubt, Use a Function
A clearly named method is almost always safer than an obscure operator. Reserve overloading for when it truly improves readability.
data class Temperature(val c: Int) {
fun warmerThan(o: Temperature) = c > o.c
}
fun main() {
println(Temperature(30).warmerThan(Temperature(20)))
}Quick Check
Test your understanding of operator overloading best practices.
Recap
You learned operator overloading best practices:
- Overload only when meaning is obvious and conventional.
- Prefer immutable, same-type returns; keep results chainable.
- Separate
plus(value) fromplusAssign(mutation). - Keep
equals/hashCodeconsistent; prefer named functions when clearer.
data class V(val x: Int) {
operator fun plus(o: V) = V(x + o.x)
}
fun main() {
println((V(2) + V(5)).x)
}Frequently asked questions
Is the “Best Practices” lesson free?
Yes — the full text of “Best Practices” is free to read here on the web, and the Kotlin Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Kotlin Academy course, upgrade to CoddyKit PRO.
What will I learn in “Best Practices”?
Keep operators intuitive. You practise Kotlin Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Kotlin Academy?
No prior experience is required. Kotlin Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Best Practices” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Kotlin Academy lesson?
Yes. Every Kotlin Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Operator Functions
- Comparison Operators
- Index and Invoke
- Best Practices