Menu
Coddy logo textTech

Default Methods

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

An interface method can have a body. This default implementation is used by every class that does not override it:

interface Greeter {
    val name: String
    fun greet() = "Hello, I am $name"
}
class Robot(override val name: String) : Greeter
class Pirate(override val name: String) : Greeter {
    override fun greet() = "Ahoy! $name here"
}

Inside main:

println(Robot("R2").greet())
println(Pirate("Anne").greet())

Output:

Hello, I am R2
Ahoy! Anne here

Default methods are written in terms of the interface's other members. A class provides the few members that differ and receives the rest:

interface Priced {
    val cents: Int
    fun formatted() = "$%d.%02d".format(cents / 100, cents % 100)
    fun isAffordable(budget: Int) = cents <= budget
}
class Coffee : Priced {
    override val cents = 450
}

Inside main:

val c = Coffee()
println(c.formatted())
println(c.isAffordable(400))

Output:

$4.50
false

Properties can have a default getter, but an interface has no backing fields, so it cannot store a value. A property with an initializer does not compile; a getter that computes the value does:

interface Box {
    val width: Int
    val height: Int
    val area: Int
        get() = width * height
    // val count = 0      // error: property initializers are not allowed in interfaces
}
class Tile(override val width: Int, override val height: Int) : Box

Inside main:

println(Tile(3, 4).area)

Output:

12

An override can still use the default implementation. Inside the class, super.method() calls the interface's version:

interface Priced {
    val cents: Int
    fun formatted() = "$%d.%02d".format(cents / 100, cents % 100)
}
class Coffee : Priced {
    override val cents = 450
    override fun formatted() = "coffee " + super.formatted()
}

Inside main:

println(Coffee().formatted())

Output:

coffee $4.50
challenge icon

Challenge

Easy

The interface Priced has price (in cents). Give it a default formatted() that returns $4.50 and a default isAffordable(budget) that returns whether the price is at most the budget. Coffee costs 450 and replaces formatted() with coffee $4.50, reusing the default through super. Sandwich(price) uses both defaults.

The supplied code reads a budget in cents and then lines coffee or sandwich,650. It prints formatted() and yes or no for each item.

Your code goes in Priced.kt, Coffee.kt and Sandwich.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 budget = input[0].toInt()
    for (line in input.drop(1)) {
        val p = line.split(",")
        val item: Priced = if (p[0] == "coffee") Coffee() else Sandwich(p[1].toInt())
        println("${item.formatted()} ${if (item.isAffordable(budget)) "yes" else "no"}")
    }
}
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