Menu
Coddy logo textTech

Enum Classes

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

An enum class declares a type with a fixed set of values, its constants. Each constant is an object of the enum with a name and an ordinal, its position starting at 0. entries lists them in order:

enum class Direction { NORTH, EAST, SOUTH, WEST }

Inside main:

val d = Direction.EAST
println(d)
println(d.ordinal)
println(Direction.entries)

Output:

EAST
1
[NORTH, EAST, SOUTH, WEST]

Enum constants can have properties, passed to the enum's constructor, and the enum can declare methods. A semicolon ends the list of constants before the members:

enum class Coin(val cents: Int) {
    PENNY(1), NICKEL(5), DIME(10), QUARTER(25);

    fun label() = "${name.lowercase()} ($cents c)"
}

Inside main:

println(Coin.DIME.label())
println(Coin.entries.sumOf { it.cents })

Output:

dime (10 c)
41

A when over an enum that lists every constant needs no else, and the compiler reports a constant that is missing. valueOf("SOUTH") finds a constant by its exact name and throws for an unknown one, so input is usually matched with entries.find:

enum class Direction { NORTH, EAST, SOUTH, WEST }

fun turnRight(d: Direction) = when (d) {
    Direction.NORTH -> Direction.EAST
    Direction.EAST -> Direction.SOUTH
    Direction.SOUTH -> Direction.WEST
    Direction.WEST -> Direction.NORTH
}

fun parse(text: String) = Direction.entries.find { it.name == text.uppercase() }

Inside main:

println(turnRight(Direction.valueOf("SOUTH")))
println(parse("north"))
println(parse("up"))

Output:

WEST
NORTH
null

A constant can have its own body and override a method there. Declaring the method abstract in the enum forces every constant to implement it:

enum class Op(val symbol: String) {
    PLUS("+") {
        override fun apply(a: Int, b: Int) = a + b
    },
    TIMES("*") {
        override fun apply(a: Int, b: Int) = a * b
    };

    abstract fun apply(a: Int, b: Int): Int
}

Inside main:

for (op in Op.entries) println("6 ${op.symbol} 3 = ${op.apply(6, 3)}")

Output:

6 + 3 = 9
6 * 3 = 18
challenge icon

Challenge

Easy

Complete the enum Size with the constants SMALL (250 ml, price 300), MEDIUM (350 ml, 380) and LARGE (500 ml, 450), prices in cents. label() returns medium (350 ml): 3.80, and upsize() returns the next larger size, or the same size for LARGE. The companion's parse(text) finds a size by its name ignoring case, or by its first letter (s, M), and returns null otherwise.

The supplied code reads orders such as medium, L or up small (the upsized drink) and prints each label or unknown size x, and finally total: 11.10.

Your code goes in Size.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()
    var total = 0
    for (line in input) {
        val upsize = line.startsWith("up ")
        val size = Size.parse(line.removePrefix("up "))
        if (size == null) {
            println("unknown size $line")
            continue
        }
        val chosen = if (upsize) size.upsize() else size
        println(chosen.label())
        total += chosen.price
    }
    println("total: %d.%02d".format(total / 100, total % 100))
}
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