Menu
Coddy logo textTech

Extension Functions

Part of the Object Oriented Programming section of Coddy's Kotlin journey. Lesson 30 of 57.

An extension function adds a function to an existing type without changing the type's source code. Its name is written after the receiver type, and inside it this refers to the receiver, which can also be left out:

fun String.shout() = uppercase() + "!"
fun Int.isEven() = this % 2 == 0

Inside main:

println("hello".shout())
println(7.isEven())
println(listOf(1, 2, 3, 4).count { it.isEven() })

Output:

HELLO!
false
2

Extensions work on your own classes too, and extension properties add computed properties. An extension cannot add stored state, and it only reaches the public members of its receiver:

class Temperature(val celsius: Double)

val Temperature.fahrenheit: Double
    get() = celsius * 9 / 5 + 32

fun Temperature.describe() = "$celsius C is $fahrenheit F"

Inside main:

println(Temperature(100.0).describe())

Output:

100.0 C is 212.0 F

Extensions are resolved statically: the declared type of the expression picks the extension when the program is compiled, not the object's class. This is the main difference from an overridden member:

open class Shape {
    open fun member() = "shape member"
}
class Circle : Shape() {
    override fun member() = "circle member"
}

fun Shape.ext() = "shape extension"
fun Circle.ext() = "circle extension"

Inside main:

val s: Shape = Circle()
println(s.member())
println(s.ext())

Output:

circle member
shape extension

When the class already has a member with the same signature, the member always wins. Use members for behaviour that belongs to the type and may be overridden; use extensions for helpers added from outside, such as formatting for a class you do not own:

class Robot {
    fun greet() = "member greet"
}

fun Robot.greet() = "extension greet"
fun Robot.wave() = "extension wave"

Inside main:

val r = Robot()
println(r.greet())
println(r.wave())

Output:

member greet
extension wave
challenge icon

Challenge

Easy

Money(cents) is supplied in Money.kt. Write extensions for it in MoneyExtensions.kt: the extension properties Int.dollars and Int.cents, which turn a number into Money (12.dollars is 1200 cents), Money.format(), which returns $12.50 (or -$3.05 for negative amounts), List<Money>.total(), which returns the sum as Money, and Money.split(parts), which splits into parts amounts that differ by at most one cent, with the larger ones first.

The supplied code reads lines 12 dollars or 50 cents and a last line with the number of parts. It prints every amount, total: $12.50 and split 3: $4.17 $4.17 $4.16.

Your code goes in MoneyExtensions.kt and Money.kt. Main.kt holds the supplied input/output code and cannot be edited.

Try it yourself

fun main() {
    // Supplied input/output code: keep it as it is
    val input = generateSequence(::readLine).toList()
    val amounts = input.dropLast(1).map { line ->
        val (n, unit) = line.split(" ")
        if (unit == "dollars") n.toInt().dollars else n.toInt().cents
    }
    for (m in amounts) println(m.format())
    val total = amounts.total()
    println("total: ${total.format()}")
    val parts = input.last().toInt()
    println("split $parts: " + total.split(parts).joinToString(" ") { it.format() })
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming

Practice on your own: Kotlin playground