skip to content

What does the `invoke` operator function do in Kotlin, and how do you make an instance of your own class callable like a function?

level: juniorimportance: must knowfreq 55%

answer

  1. obj() compiles to obj.invoke()
  2. operator keyword is mandatory
  3. lambdas implement FunctionN.invoke
  4. can overload with many signatures
  5. works on class, object, companion

basics

~10 s

Declaring operator fun invoke(...) on a class lets you call an instance with parentheses, like obj(), instead of writing obj.invoke(). It turns an object into something you can call like a function.

solid answer

~40 s

`invoke` is a Kotlin operator-overloading convention. If a class declares `operator fun invoke(args)`, then `obj(args)` is syntactic sugar that compiles to `obj.invoke(args)`. The `operator` keyword is mandatory; without it the call-with-parentheses syntax won't compile (you'd have to call `.invoke()` explicitly). You can overload `invoke` with multiple signatures (different parameter lists, return types, even `suspend`). This is how function types and lambdas work under the hood: a lambda is an object implementing `FunctionN<...>` whose single member is `operator fun invoke`. Common real uses: callable factory objects, stateful counters, configuration builders, and wrapping a strategy as a value you can call. The receiver can be a normal class, an `object`, or a `companion object` (making `ClassName()` -style calls possible).

code

kotlin · 6 lines
kotlin
class Multiplier(val factor: Int) {
    operator fun invoke(x: Int): Int = x * factor
}

val triple = Multiplier(3)
println(triple(10)) // 30, same as triple.invoke(10)

go deeper

for a junior

Knows obj() desugars to obj.invoke() and that operator is required.

for a middle

Can write overloads and connect it to function types being FunctionN.invoke.

for a senior

Explains companion-object factory pattern and call-site resolution clearly.

for a principal

Discusses API ergonomics/readability trade-offs of making types callable vs named methods.

## What `invoke` is Kotlin lets certain function names map to operator syntax. `invoke` is the convention for the *call* operator — parentheses. When the compiler sees `obj(args)` and `obj` is **not** a class reference being constructed, it rewrites the call to `obj.invoke(args)`. To opt in, the function must be marked with the `operator` keyword: ```kotlin class Greeter(val greeting: String) { operator fun invoke(name: String): String = "$greeting, $name!" } val hello = Greeter("Hello") println(hello("Ada")) // "Hello, Ada!" -> compiles to hello.invoke("Ada") println(hello.invoke("Bob"))// equivalent explicit form ``` ## Rules - The `operator` modifier is **required**. A plain `fun invoke(...)` exists as a normal method but `obj(...)` syntax will not compile against it. - `invoke` can take **any** parameter list, including none (`obj()`), defaults, and `vararg`. It can return anything, including `Unit`. - You may **overload** `invoke` with several signatures on one type; overload resolution picks the matching one. - It works on classes, `object` singletons, and `companion object` (which enables `ClassName(...)`-like calls that are really `ClassName.invoke(...)`). ## Why it matters: lambdas and function types A Kotlin function type like `(Int) -> String` is really the interface `Function1<Int, String>`, whose single method is `operator fun invoke(p1: Int): String`. So when you write `val f: (Int) -> String = { it.toString() }` and then call `f(3)`, you are invoking `f.invoke(3)`. This is why a custom class that defines `invoke` can stand in conceptually for a lambda. ## Typical uses - **Callable objects / strategies**: hold state in a class but call it like a function. - **Factories**: a `companion object` with `invoke` lets `Foo(...)` build instances while keeping the real constructor private. - **DSLs**: callable builder objects read naturally.

  • What happens if you write `fun invoke(...)` without the `operator` keyword?
    It becomes an ordinary method; `obj(...)` syntax won't compile. You must call it explicitly as `obj.invoke(...)`.
  • Can `invoke` take no parameters?
    Yes. `operator fun invoke()` makes `obj()` valid — useful for lazy/parameterless callable objects or suppliers.

A class with invoke is like a vending machine: it is an object that just sits there, but you can 'press the button' (the parentheses) to make it produce a result.

saying these in an interview costs you the question

  • Claiming `obj()` always means constructor invocation
  • Forgetting the `operator` keyword is required
  • Saying `invoke` cannot be overloaded
  • Thinking only `object`/singletons can define it
  • Believing lambdas are unrelated to `invoke`

context