skip to content

Enums with Behavior

Each enum constant can supply its own body overriding an abstract member, which gives you a type-safe strategy table with no if-chains. This is the answer to 'how would you attach different behavior to each case' without leaving the enum.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

In Kotlin, how do you make each enum constant run its own different code for the same operation? Show a small example.

level: juniorimportance: must knowfreq 55%

answer

  1. abstract member in the enum
  2. override in braces after each constant
  3. semicolon ends the constant list
  4. each constant = anonymous subclass
  5. type-safe strategy, no when chain

basics

~10 s

Declare an abstract function in the enum, then give each constant a body in curly braces that overrides it. Calling the function on a constant runs that constant's version.

solid answer

~40 s

Define an `abstract` member (function or property getter) in the enum class body. Each constant then supplies its own implementation in an anonymous-class body — the braces right after the constant's name, with the function marked `override`. Each constant is effectively a tiny subclass of the enum type that fills in the abstract member. Calling the member dispatches to the matching constant's override at runtime, so `Operation.PLUS.apply(2, 3)` and `Operation.TIMES.apply(2, 3)` run different code. This is the type-safe strategy pattern: the compiler forces every constant to implement the abstract member, so you can never forget one, and there is no `when`/`if` chain to maintain.

code

kotlin · 12 lines
kotlin
enum class Operation {
    PLUS { override fun apply(a: Int, b: Int) = a + b },
    MINUS { 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
}

fun main() {
    println(Operation.PLUS.apply(4, 2))  // 6
    println(Operation.TIMES.apply(4, 2)) // 8
}

go deeper

for a junior

Can write the abstract function plus per-constant override and explain that each constant runs its own code.

for a middle

Explains the semicolon rule and that each constant is an anonymous subclass with virtual dispatch.

for a senior

Frames it as the type-safe strategy pattern and contrasts with when, noting compile-time exhaustiveness.

for a principal

Discusses when per-constant bodies hurt (generated class bloat, testing) vs centralized strategy, and migration tradeoffs.

## The idea An **enum class** is a fixed set of named constants. Normally every constant behaves identically. "Enums with behavior" means each **constant** carries its *own* implementation of a shared operation. ## The mechanism: abstract member + per-constant body You declare an `abstract` function (or `abstract val` with a custom getter) inside the enum body. Because it is abstract it has no implementation there — so **each constant must provide one**. A constant provides it by writing an **anonymous-class body**: open curly braces right after the constant name and `override` the member. ```kotlin enum class Operation { 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 } val r = Operation.TIMES.apply(2, 3) // 6 ``` Key syntax points: - The constant list ends with a **semicolon (`;`)** before any members are declared. This semicolon is mandatory when the enum has a body. - Each `{ ... }` after a constant is an **anonymous subclass** of the enum type. Under the hood the compiler generates a synthetic class per such constant. - Every constant must override every abstract member, or the code does not compile — that is the "type-safe" guarantee. ## Why this over `when` A `when (this)` inside one shared function also works, but: - The compiler does **not** force you to handle a newly added constant unless the `when` is exhaustive *and* used as an expression. - Behavior is scattered or centralized away from the constant. The per-constant body keeps each constant's logic next to its name. ## Dispatch Calling `someConstant.apply(...)` uses normal virtual dispatch: the runtime type is the synthetic subclass for that constant, so its `override` runs. This is **polymorphism**, just with a closed, finite set of subtypes. ## Related keywords `enum class`, `abstract`, `override`, anonymous-class body, the constant-list-terminating `;`.

  • What happens if you add a constant but forget to override the abstract function?
    It does not compile — the new constant's anonymous body must implement every abstract member, so the compiler flags it immediately.
  • Why is the semicolon after the last constant required here?
    Because the enum has further members (the abstract function); the `;` separates the constant list from those member declarations.

Each constant is a vending-machine slot that holds its own recipe; pressing the slot runs that recipe.

saying these in an interview costs you the question

  • Thinking you must use a giant when(this) instead of per-constant bodies
  • Forgetting the mandatory semicolon after the constant list
  • Saying enums cannot have abstract methods
  • Believing the constant body is a lambda rather than an anonymous subclass
  • Not marking the per-constant function override

context

open as a page

Can a constant that has its own override body also pass constructor arguments? Show how per-constant bodies combine with a primary constructor and shared state.

level: middleimportance: should knowfreq 30%

basics

~10 s

Yes. Put the constructor arguments in parentheses after the constant name, then the override body in braces. Each constant can carry shared data and still have its own behavior.

open as a page

Explain exactly what the Kotlin compiler generates for an enum that has per-constant anonymous-class bodies, and why a semicolon after the constant list is mandatory.

level: middleimportance: should knowfreq 35%

basics

~10 s

Each constant with its own body becomes a separate hidden subclass of the enum. The semicolon is needed to mark where the constant list ends and member declarations begin.

open as a page

When would you prefer per-constant enum bodies over a sealed class hierarchy, and how do per-constant abstract property overrides work?

level: seniorimportance: should knowfreq 28%

basics

~20 s

Use per-constant enum bodies for a fixed, small set of singletons that share one operation. Use sealed classes when variants carry different data shapes or need multiple instances. Property overrides use an abstract val with a per-constant getter.

open as a page

A teammate has a bodied enum where each constant overrides apply(). They want to add a brand-new operation that depends on each constant. Compare extending the enum with a new abstract method vs handling it in an external when, and discuss the dispatch and maintainability tradeoffs.

level: seniorimportance: nice to knowfreq 18%

basics

~10 s

Adding a new abstract method forces every constant to implement it (compile-safe, behavior stays with the constant). An external when keeps the enum closed but risks forgetting a constant unless the when is exhaustive.

open as a page