Extension Functions Workbook
Practice problems for Extension Functions: Add Methods to Classes You Don’t Own. Each takes a minute or two. Write your own answer first, then click Show answer — nothing here is a trick question, just direct practice of the syntax from the lesson.
declaring extensions
1. Extend String
Write an extension shout() on String that returns the uppercased text with a ! appended.
Show answer Hide answer
fun String.shout() = uppercase() + "!"
"hello".shout() // "HELLO!"this (the receiver) is implicit, so uppercase() reads like a member call.
2. Extend Int
Write an extension isEven() on Int returning whether it’s even.
Show answer Hide answer
fun Int.isEven() = this % 2 == 0
4.isEven() // true 3. Extend a generic type
Write List<Int>.secondOrNull() that returns the second element, or null if the list is too short.
Show answer Hide answer
fun List<Int>.secondOrNull(): Int? = if (size >= 2) this[1] else null properties and nullable receivers
4. An extension property
Write a read-only extension property firstWord on String returning everything before the first space.
Show answer Hide answer
val String.firstWord: String
get() = substringBefore(" ")
"hello world".firstWord // "hello"An extension property has no backing field, so it must compute its value in a getter.
5. A nullable receiver
Write orEmpty() on String? that returns "" when the receiver is null, otherwise the string itself.
Show answer Hide answer
fun String?.orEmpty(): String = this ?: ""
val name: String? = null
name.orEmpty() // ""Extending a nullable type lets the extension handle null itself — the call is safe with no ?..
resolution rules
6. Make it polymorphic
Extensions resolve statically, so with fun Animal.speak() and fun Dog.speak(), a val pet: Animal = Dog() calls the Animal one. Rewrite speak as member functions so pet.speak() returns "woof".
Show answer Hide answer
open class Animal { open fun speak() = "generic" }
class Dog : Animal() { override fun speak() = "woof" }
val pet: Animal = Dog()
pet.speak() // "woof" — members dispatch on the runtime type 7. Members win
Write a class Box with a member size() returning 1, plus an extension Box.size() returning 99. What does Box().size() return?
Show answer Hide answer
class Box { fun size() = 1 }
fun Box.size() = 99
Box().size() // 1 — a member always wins over an extension 8. Chain reads top-to-bottom
Rewrite reversed(trimmed(input)) (two hypothetical helpers) as a readable extension chain input.trimmed().reversed() — just write the two extension signatures that make it possible.
Show answer Hide answer
fun String.trimmed() = trim()
fun String.reversed() = StringBuilder(this).reverse().toString()Extensions let calls read in subject-verb order instead of inside-out.
9. Extend with a parameter
Write an extension repeatTimes(n: Int) on String returning the string concatenated n times.
Show answer Hide answer
fun String.repeatTimes(n: Int) = repeat(n) 10. Nullable receiver, used safely
Given name: String?, call your orEmpty() extension on it directly. Why is no ?. needed?
Show answer Hide answer
name.orEmpty()Because the receiver type is String?, the extension itself accepts null — so the plain dot call is safe.
Back to the lesson, Extension Functions, or on to the next one: equality.