Extension Functions
Extensions let you add functions and properties to a type without modifying its
source — even types you do not own, like String or List.
Extension functions
fun String.isPalindrome(): Boolean {
val clean = lowercase().filter { it.isLetterOrDigit() }
return clean == clean.reversed()
}
"Level".isPalindrome() // true
"hello".isPalindrome() // false
Inside the function, this refers to the receiver (the String). You can omit
this, as with lowercase() above.
Extension properties
val String.firstWord: String
get() = substringBefore(" ")
"hello world".firstWord // "hello"
Extension properties cannot have backing fields, so they must be computed.
infix functions
An infix function can be called without the dot and parentheses:
infix fun Int.clampedTo(max: Int): Int = if (this > max) max else this
10 clampedTo 5 // 5
3 clampedTo 5 // 3
(to, used to build map pairs, is itself an infix extension.)
vararg and local helpers, revisited
Extensions combine well with other features:
fun <T> List<T>.second(): T = this[1]
fun StringBuilder.appendLineIf(condition: Boolean, line: String) {
if (condition) appendLine(line)
}
How extensions work
Extensions are resolved statically by the declared type of the receiver — they are syntactic sugar for a function that takes the receiver as its first argument. They do not actually modify the class or allow overriding its members.
Exercises
-
Write an extension
Int.isEven(): Boolean. -
Write
String.isPalindrome(): Booleanthat ignores case and non-letters (so"A man, a plan, a canal: Panama"is a palindrome).Solution
fun String.isPalindrome(): Boolean {
val clean = lowercase().filter { it.isLetterOrDigit() }
return clean == clean.reversed()
}
</details>
This solution is in examples/core/part3/ and is tested by CI.
Previous: Objects & Companions · Next: Part 4: Collections & Generics