skip to content

When should you prefer a function-type alias over a `fun interface` (SAM) for a callback, and what are the trade-offs?

level: seniorimportance: should knowfreq 40%

answer

  1. alias = nickname, fun interface = real type
  2. interface gives nominal identity + defaults
  3. alias zero-cost, SAM may allocate
  4. overload/`is` only with fun interface
  5. Java sees fun interface, not alias

basics

~20 s

Use a typealias when you only want a readable name for a lambda signature with no extra behavior. Use a fun interface when you need a real distinct type, default methods, or nominal type safety. The alias is just a name; the interface is a true type.

solid answer

~50 s

A function-type alias (`typealias OnClick = (View) -> Unit`) is a compile-time nickname: zero runtime type, interchangeable with the raw function type, but no nominal identity, no members, and no way to add default methods or named parameters. A `fun interface OnClick { fun invoke(v: View) }` is a real nominal type: it can have default/extra methods, distinguishes itself from other interfaces with the same shape, supports `is` checks, and still allows lambda (SAM) construction. Prefer the alias for purely internal readability of common signatures (predicates, reducers). Prefer the `fun interface` when the callback is a public API contract you want to evolve, when you need overload resolution by type, default behavior, or distinct types for two same-shaped callbacks. Trade-off: `fun interface` allocates an object per SAM conversion (unless inlined), while an alias is free.

code

kotlin · 10 lines
kotlin
// Same shape, different intent — aliases can't keep them apart:
typealias OnClick = (View) -> Unit
typealias OnLongClick = (View) -> Unit  // == OnClick, interchangeable!

// fun interface keeps them distinct:
fun interface Click { fun on(v: View) }
fun interface LongClick { fun on(v: View) }

fun set(c: Click) {}
// set(LongClick { }) // compile error: distinct nominal types

go deeper

for a junior

Knows both let you pass a lambda for a callback.

for a middle

Can state that fun interface is a real type with possible default methods while an alias is just a name.

for a senior

Weighs nominal identity, overloads, defaults, Java interop, and SAM allocation cost to pick correctly.

for a principal

Sets team guidance: aliases for internal readability, fun interfaces for public evolvable contracts; considers performance and interop.

## The two tools **Function-type alias** — `typealias` naming a function type: ```kotlin typealias OnClick = (View) -> Unit ``` A pure compile-time alias. It expands to `(View) -> Unit` (`Function1<View, Unit>`). No new type, no members, no runtime presence. **Functional interface (`fun interface`)** — a SAM interface with exactly one abstract method: ```kotlin fun interface OnClick { fun onClick(view: View) fun describe(): String = "click handler" // default method allowed } ``` A real **nominal type**. SAM conversion lets you still pass a lambda: `setListener(OnClick { v -> ... })` or, in a SAM-conversion position, just `{ v -> ... }`. ## Decision factors - **Nominal identity / type safety.** Two aliases that both expand to `(View) -> Unit` are *the same* type and freely mixed. Two `fun interface`s of identical shape are *different* types — the compiler stops you from passing one where the other is required. Choose the interface when distinct callbacks must not be confused (e.g., `OnClick` vs `OnLongClick`). - **Members / defaults.** Only a `fun interface` can carry extra or default methods, constants, or named, documented parameters. An alias has none. - **Overload resolution.** You can overload a function by two different `fun interface` types; you cannot overload by two aliases of the same underlying type. - **`is`/`as` checks & reflection.** A `fun interface` produces a checkable type; an alias does not. - **Performance.** A SAM conversion to a `fun interface` typically allocates an adapter object (unless the call site is `inline`). An alias has zero runtime cost. For hot paths or high-frequency callbacks, an alias (or `inline` higher-order function) avoids allocations. - **Java interop.** A `fun interface` is a real interface visible to Java; an alias is invisible to Java callers (they see `Function1`). ## Rule of thumb - Internal, ubiquitous signatures where readability is the only goal → **alias**. - Public, evolvable API contracts; need distinct types, defaults, named params, or Java interop → **fun interface**. ```kotlin // Alias: just readability typealias Validator<T> = (T) -> Boolean // fun interface: distinct nominal type + default method + Java-visible fun interface Validator2<T> { fun validate(value: T): Boolean fun negate(): Validator2<T> = Validator2 { !validate(it) } } ```

  • Does a SAM conversion to a fun interface allocate?
    Usually yes — an adapter object is created per conversion, unless the receiving higher-order function is `inline`, which can elide it.
  • Can you overload a function on two type aliases of the same function type?
    No. They're the same type, so it's a conflicting-overload error. Two distinct fun interfaces would work.

An alias is a sticky note relabeling an existing box; a fun interface is a new, labeled box you can put extra compartments in.

saying these in an interview costs you the question

  • Saying aliases and fun interfaces are equivalent in type safety
  • Claiming a typealias can have default methods
  • Believing aliases are visible as real types to Java callers
  • Ignoring SAM allocation cost when recommending fun interface for hot paths
  • Thinking you can overload by two same-shaped aliases

context