Why can't you SAM-convert a lambda for a Kotlin interface by default, and how do you enable it?
answer
- Java interfaces: auto SAM; Kotlin interfaces: not by default
- fun interface = opt-in (Kotlin 1.4+)
- Kotlin has function types, avoids redundancy
- One abstract method, no abstract properties
- Otherwise use object : Iface { }
basics
~10 sBy default Kotlin only auto-converts lambdas for Java single-method interfaces. For a Kotlin interface you mark it 'fun interface'. Without that, you must write a full object expression implementing the interface.
solid answer
~40 sKotlin's SAM conversion historically applied only to Java interfaces because Kotlin already has first-class function types ((T) -> R), so the language designers wanted you to use function types rather than declare single-method interfaces. To opt a Kotlin interface into lambda conversion you declare it with the fun interface modifier (a 'functional interface', since Kotlin 1.4). Then a lambda matching its single abstract method is auto-converted. Without fun, passing a lambda is a type error and you must use an object : MyInterface { ... } expression. The reasoning: avoid two redundant ways (function types vs interfaces) of expressing the same callback, while still allowing interfaces when you need a named type, extra members, or to attach extensions.
code
kotlin · 11 linesfun interface IntPredicate {
fun accept(i: Int): Boolean
}
val isEven = IntPredicate { it % 2 == 0 } // SAM-converted lambda
println(isEven.accept(4)) // true
// Plain interface without 'fun' would reject the lambda:
interface Plain { fun accept(i: Int): Boolean }
val p = object : Plain { override fun accept(i: Int) = i > 0 }
println(p.accept(3)) // truego deeper
Knows you can't pass a lambda to a plain Kotlin interface and must use object : Iface{}.
Knows the fun interface modifier enables SAM conversion and the one-abstract-method constraint.
Explains the design rationale (function types vs interfaces) and when each is the right tool.
Discusses API-design tradeoffs: named functional types, extension surface, and avoiding redundant idioms across a codebase.
## The default rule SAM conversion is **automatic only for Java interfaces**. For a Kotlin interface, even one with a single abstract method, a lambda is **not** accepted by default: ```kotlin interface Handler { fun handle(event: String) } // val h: Handler = { e -> println(e) } // COMPILE ERROR val h = object : Handler { // must spell out the object override fun handle(event: String) = println(event) } ``` ## Why the restriction exists Kotlin has **first-class function types** like `(String) -> Unit`. The designers reasoned that if you just want to pass behavior, you should use a function type — not declare a single-method interface. Allowing automatic SAM conversion for every Kotlin interface would create two overlapping idioms for the same job. Java has no function types, so SAM conversion is the only ergonomic option there, which is why it's enabled for Java interfaces. ## Opting in: `fun interface` Since Kotlin 1.4 you can declare a **functional interface** with the `fun` modifier. It must have exactly one abstract method: ```kotlin fun interface Handler { fun handle(event: String) } val h: Handler = { e -> println(e) } // now legal, SAM-converted h.handle("click") ``` Rules for `fun interface`: - Exactly **one abstract method** (it may have additional non-abstract members and properties with bodies). - It **cannot** have abstract properties. - Once marked, lambdas and method references convert to it. ## When to use a `fun interface` vs a function type - Use a **plain function type** `(T) -> R` for simple, anonymous callbacks. - Use a **`fun interface`** when you want a **named type**, want to add **extension functions** on it, need it to participate in a class hierarchy, or want a clearer API surface (e.g. `Predicate`, `Validator`). ## Explicit conversion via the synthetic constructor For either Java SAM interfaces or `fun interface`s, the compiler also generates a **SAM constructor** — an invocation that looks like a constructor and takes a lambda, e.g. `Handler { e -> ... }` or `Runnable { ... }`. This is useful to disambiguate overloads or to store the converted instance in a variable.
- Can a fun interface have an abstract property?No. A functional interface may have only one abstract member and it must be a method; abstract properties are not allowed.
- If you already have a function type, why ever define a fun interface?To give the callback a named type, attach extension functions, fit a class hierarchy, or expose a clearer, self-documenting API.
Java interfaces get a courtesy auto-translator at the border; Kotlin interfaces must apply for the 'fun' visa before lambdas may cross.
saying these in an interview costs you the question
- Claiming lambdas auto-convert to any Kotlin interface with one method
- Not knowing the fun interface modifier exists
- Saying a fun interface can have multiple abstract methods
- Thinking fun interface allows abstract properties