skip to content

Plain Function Types (A)->B

(Int, Int) -> Int is a real type, and on the JVM it becomes one of the FunctionN interfaces with an invoke method. Knowing that desugaring is what makes lambda allocation and inlining questions answerable.

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

questions

5

How do you read and write a plain Kotlin function type such as (Int, Int) -> String, and what does () -> Unit mean?

level: juniorimportance: must knowfreq 80%

answer

  1. Parentheses = inputs, arrow = output
  2. () -> Unit is the void callback
  3. Lambda or ::reference produces the value
  4. f(x) is sugar for f.invoke(x)
  5. Unit is Kotlin's void

basics

~20 s

It describes a value that is itself a function. The part in parentheses lists the input types, the arrow points to the result type. () -> Unit means: takes no input and returns nothing useful.

solid answer

~40 s

A function type is the type of a value that can be called. The syntax is (ParamTypes) -> ReturnType. The comma-separated types in parentheses are the parameter types (zero or more); the type after -> is the return type. (Int, Int) -> String is a function taking two Ints and producing a String. () -> Unit takes no parameters and returns Unit, Kotlin's equivalent of void, so it is used for side-effecting callbacks like onClick. You assign such a value with a lambda { a, b -> ... } or a function reference (::foo), store it in a val/var, pass it as a parameter, or return it. You call it either with normal call syntax f(1, 2) or explicitly f.invoke(1, 2).

code

kotlin · 6 lines
kotlin
val onClick: () -> Unit = { println("clicked") }
val combine: (Int, Int) -> String = { a, b -> "sum=${a + b}" }

onClick()                  // prints: clicked
println(combine(2, 3))     // prints: sum=5
println(combine.invoke(4, 5)) // same call, explicit invoke

go deeper

for a junior

Can read (A, B) -> C, knows () -> Unit is a no-arg side-effect callback, and can call it with f().

for a middle

Distinguishes Unit from null/void, knows lambdas and ::references both yield function-type values, and uses invoke explicitly.

for a senior

Frames function types as first-class values underpinning higher-order functions and callback APIs; mentions Nothing vs Unit nuance.

for a principal

Connects the notation to API design choices (callback shape, Unit-returning side effects) and to how the compiler desugars it to interfaces.

## What a function type is In Kotlin, functions are first-class values: you can store them in variables, pass them as arguments, and return them. The **type** of such a value is a **function type**. ## The notation The general shape is: ``` (ParameterTypes) -> ReturnType ``` - Inside the parentheses you list the **parameter types**, separated by commas. There can be zero, one, or many. - After the `->` arrow comes the **return type**. Examples: - `() -> Unit` — no parameters, returns `Unit`. `Unit` is Kotlin's analogue of Java's `void`: a type with exactly one value, also written `Unit`. Used for callbacks that only perform a side effect. - `(Int) -> Int` — takes one `Int`, returns an `Int` (e.g. a squaring function). - `(Int, Int) -> String` — takes two `Int`s, returns a `String`. - `(String) -> Boolean` — a predicate. ## Creating values of a function type ```kotlin val log: () -> Unit = { println("tick") } val add: (Int, Int) -> Int = { a, b -> a + b } val len: (String) -> Int = String::length // function reference ``` A **lambda** `{ params -> body }` and a **function reference** `::name` are the two common ways to produce such a value. ## Calling it ```kotlin log() // invoke syntax val s = add(2, 3) // 5 val n = len.invoke("hi") // explicit invoke, same as len("hi") ``` Under the hood `f(args)` is sugar for `f.invoke(args)`. ## Why it matters Function types are the foundation of higher-order functions like `map`, `filter`, `forEach`, and of callback-style APIs. Knowing how to read `(A, B) -> C` lets you understand any such signature at a glance.

  • What is the difference between () -> Unit and () -> Nothing?
    () -> Unit returns normally with the Unit value; () -> Nothing never returns normally (it always throws or loops forever). Nothing is the bottom type with no instances.
  • Is (Int) -> Int the same type as a method named square?
    No. (Int) -> Int is a type; square is a declaration. But you can obtain a value of that type from the method via the reference ::square.

A function type is like a job description: it states what inputs a worker accepts and what they hand back, without naming any specific worker.

saying these in an interview costs you the question

  • Reading the arrow backwards (thinking the part after -> is the input)
  • Saying () -> Unit returns null instead of the Unit value
  • Claiming you must always write .invoke() to call it
  • Confusing the function type with a function declaration

context

open as a page

What do plain function types like (Int, Int) -> Int compile to on the JVM, and how does that relate to FunctionN interfaces and invoke?

level: middleimportance: should knowfreq 55%

basics

~10 s

A function type is really a regular interface in disguise. (Int, Int) -> Int becomes Function2<Int, Int, Int>, an interface with one method called invoke. Calling the function calls invoke.

open as a page

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.

level: middleimportance: should knowfreq 45%

basics

~10 s

Calling 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.

open as a page

Distinguish these function types: () -> Unit, (Unit) -> Unit, and (Int) -> Unit. Why does arity matter and what trips people up with Unit?

level: seniorimportance: should knowfreq 35%

basics

~20 s

() -> Unit takes no arguments. (Unit) -> Unit takes one argument whose type happens to be Unit. (Int) -> Unit takes one Int. The number of parameters (the arity) is part of the type, so these are all different.

open as a page

Given the FunctionN variance (in parameters, out return), explain when one plain function type is a subtype of another, with an example.

level: principalimportance: nice to knowfreq 22%

basics

~20 s

A function can stand in for another if it accepts at least as wide a range of inputs and returns at least as specific an output. So you can use a function that takes a broader parameter type and returns a narrower result type.

open as a page