Why can you both call a function value with f() and write f.invoke()? Explain the role of the invoke operator and where it can show up.
answer
- obj(args) == obj.invoke(args)
- FunctionN supplies invoke for free
- operator fun invoke makes any object callable
- companion invoke = constructor-like factory
- nullable: must use ?.invoke()
basics
~10 sCalling something with parentheses is shorthand for calling its invoke method. Function values have invoke, so f() and f.invoke() do the same thing. Any object that defines an invoke operator becomes callable too.
solid answer
~40 sIn Kotlin, the parenthesis-call syntax obj(args) is defined as sugar for obj.invoke(args). Function types have invoke because they are FunctionN interfaces, each declaring operator fun invoke. That is why f() and f.invoke() are interchangeable. The mechanism is general: any type that declares operator fun invoke(...) gains call syntax, even non-function classes. This is used to make objects look like functions — e.g. a companion object with invoke acts as a factory called like a constructor, or a class instance acts as a callable strategy. invoke can be overloaded with different parameter lists. The explicit form f.invoke() is handy when the value is nullable: you write f?.invoke() to call it only if non-null, which you cannot express with bare parentheses.
code
kotlin · 5 linesval maybe: ((Int) -> Int)? = if (System.nanoTime() % 2 == 0L) { x -> x } else null
// Cannot write maybe?(5); must use explicit invoke:
val result = maybe?.invoke(5) // Int? — null if maybe was null
println(result)go deeper
Knows f() and f.invoke() both call the function and that invoke is what gets called.
Explains invoke as a general operator convention; uses ?.invoke for nullable function values.
Designs callable types with operator fun invoke, including companion-object factories and overloaded invoke.
Weighs readability/API ergonomics of invoke-based callables vs explicit methods and reasons about nullable-call sites.
## The convention Kotlin defines several **operator conventions** — special method names that enable syntax. For the parenthesis-call operator the method name is **`invoke`**: ``` x(a, b) ≡ x.invoke(a, b) ``` Any declaration of `operator fun invoke(...)` makes its receiver **callable** with parentheses. ## Why function values are callable A value of type `(Int) -> Int` is a `Function1<Int, Int>`, and that interface declares `operator fun invoke(p1): R`. So the call syntax is available automatically: ```kotlin val f: (Int) -> Int = { it * 2 } f(10) // 20 f.invoke(10) // 20 — exactly the same ``` ## Making your own types callable Because the convention is general, you can give ordinary classes or objects an `invoke`: ```kotlin class Greeter(val greeting: String) { operator fun invoke(name: String) = "$greeting, $name!" } val hi = Greeter("Hello") println(hi("Ann")) // Hello, Ann! -> hi.invoke("Ann") ``` A common pattern is `operator fun invoke` on a **companion object**, so the class name itself becomes a factory call: ```kotlin class Logger private constructor() { companion object { operator fun invoke(): Logger = Logger() } } val log = Logger() // looks like a constructor, runs the companion's invoke ``` ## Overloading and explicit form `invoke` can be **overloaded** with different signatures, and you may declare several. The explicit `.invoke` form is required in two situations: - **Nullable function values**: `callback?.invoke(x)` performs a safe call; you cannot write `callback?(x)`. - **Disambiguation/readability** when a value is also indexable or otherwise ambiguous. ## Key takeaways - `f(...)` is always sugar for `f.invoke(...)`. - Function types get `invoke` from `FunctionN`; any class can opt in by declaring `operator fun invoke`. - Use `?.invoke` to call a nullable function value safely.
- How do you call a nullable function value safely?Use the explicit invoke with a safe call: f?.invoke(args). Bare-parenthesis syntax f?(args) is not valid Kotlin.
- Can a regular class be called like a function without being a function type?Yes. Declare operator fun invoke on it; the class is then callable with parentheses even though its type is not a FunctionN.
invoke is like a doorbell wired to parentheses: press the parentheses and whatever invoke is behind them rings.
saying these in an interview costs you the question
- Believing only lambdas can have invoke
- Trying to write f?(x) for a nullable function value
- Thinking f() and f.invoke() are different operations
- Not realizing companion-object invoke enables constructor-like calls