skip to content

Declaration Forms

The shapes a function declaration can take — top level, nested, expression-bodied — and the parameter features that go with them: defaults, named arguments, and varargs. Interviewers grade whether you use these instead of overload piles.

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

explore

questions

page 1 of 2

What are default arguments in Kotlin, and how do they let you avoid writing multiple overloads?

level: juniorimportance: must knowfreq 80%

answer

  1. = value in the signature
  2. Replaces telescoping overloads
  3. Mix defaulted and non-defaulted params
  4. Named args skip middle params
  5. One function, many call shapes

basics

~10 s

A default argument gives a parameter a value used when the caller omits it. So one function with defaults replaces many overloaded functions that differ only by which parameters they accept.

solid answer

~40 s

In Kotlin you assign a default in the signature: fun greet(name: String, greeting: String = "Hello"). Callers can pass both arguments or just name, in which case greeting becomes "Hello". This removes the need for telescoping overloads common in Java, where you'd write greet(name) delegating to greet(name, "Hello"). Combined with named arguments, callers can skip middle parameters and set only the ones they care about: greet(name = "Sam"). Any parameter can have a default, the default can be a constant or an expression, and you can mix parameters with and without defaults. Defaults shrink the API surface and keep call sites readable while still allowing full control when needed.

code

kotlin · 8 lines
kotlin
fun connect(host: String, port: Int = 443, tls: Boolean = true): String =
    "$host:$port tls=$tls"

fun main() {
    println(connect("a.com"))                // a.com:443 tls=true
    println(connect("a.com", 80, false))     // a.com:80 tls=false
    println(connect("a.com", tls = false))   // a.com:443 tls=false
}

go deeper

for a junior

Knows the = syntax and that omitting an argument uses the default.

for a middle

Explains the named-argument interaction and mixing defaulted/non-defaulted params.

for a senior

Frames defaults as an API-design tool reducing overload sprawl and discusses call-site clarity.

for a principal

Weighs API evolution, binary compatibility, and when overloads are still warranted (e.g. Java interop).

## What a default argument is A **default argument** is a value attached to a function parameter in its declaration. If a caller does not supply that argument, Kotlin uses the default. This is written with `=` after the parameter type: ```kotlin fun greet(name: String, greeting: String = "Hello"): String = "$greeting, $name!" greet("Sam") // "Hello, Sam!" — greeting defaulted greet("Sam", "Hi") // "Hi, Sam!" greet(name = "Sam") // named argument, greeting defaulted ``` ## Why this replaces overloads In languages without defaults (like Java), you typically write **telescoping overloads** — many functions with the same name differing only in parameter count, each delegating to the fuller one: ```java String greet(String name) { return greet(name, "Hello"); } String greet(String name, String greet) { return greet + ", " + name; } ``` Kotlin collapses all of these into **one** function. Fewer functions means less code to maintain and a smaller API surface. ## Rules you should know - **Any** parameter can have a default, not just the last ones. - You can **mix** parameters with and without defaults. - The default expression can reference earlier parameters (e.g. `fun f(a: Int, b: Int = a)`). - To skip a middle parameter that has a default, use **named arguments**: `f(a = 1, c = 3)`. ## Interaction with named arguments Defaults and **named arguments** are complementary. Named arguments let you specify only the parameters you want by name, letting all others fall back to their defaults — even when the omitted ones are not at the end of the list. ```kotlin fun connect(host: String, port: Int = 443, timeoutMs: Int = 5000, tls: Boolean = true) { /* ... */ } connect("api.example.com", timeoutMs = 1000) // port and tls defaulted ```

  • Can a default expression reference an earlier parameter?
    Yes. Defaults are evaluated left to right, so a later parameter's default can use a value already bound, e.g. fun f(a: Int, b: Int = a * 2).
  • How do you skip a middle parameter that has a default?
    Use named arguments for the ones after it, e.g. f(a = 1, c = 3), letting the middle parameter take its default.

Like a form with pre-filled fields: leave them as-is or overwrite the ones you care about.

saying these in an interview costs you the question

  • Claiming only the last parameter can have a default
  • Saying defaults require named arguments always
  • Confusing default arguments with nullable types
  • Thinking Kotlin still needs telescoping overloads

context

open as a page

What is a local (nested) function in Kotlin, and what is the main reason to use one instead of a private top-level or member function?

level: juniorimportance: must knowfreq 55%

basics

~20 s

A local function is a function declared inside another function. The main reason to use one is to reuse a small piece of logic that only matters to the surrounding function, while reading its local variables directly.

open as a page

What are named arguments in Kotlin, and what call-site problems do they solve?

level: juniorimportance: must knowfreq 70%

basics

~10 s

Named arguments let you pass a value by writing the parameter's name, like draw(width = 5). This makes calls easier to read and lets you supply only the arguments you want, in any order.

open as a page

What does the :: operator do when applied to a function name, e.g. `::println` or `String::length`, and what is the resulting value?

level: juniorimportance: must knowfreq 70%

basics

~20 s

The :: operator turns a named function into a value you can store in a variable or pass to another function, instead of calling it. The result is a function object you can invoke later.

open as a page

What is a single-expression function in Kotlin, and how does its syntax differ from a regular block-body function?

level: juniorimportance: must knowfreq 70%

basics

~20 s

It is a function whose body is a single expression written after an equals sign instead of curly braces. For example: fun square(x: Int) = x * x. The result of the expression is what the function returns.

open as a page

What is a top-level function in Kotlin, and how do you declare and call one?

level: juniorimportance: must knowfreq 70%

basics

~10 s

A function written directly in a file, not inside any class. You declare it with the fun keyword at the top of the file and call it just by its name after importing it.

open as a page

What is the Unit type in Kotlin, and how does it differ from Java's void? When can you omit it from a function signature?

level: juniorimportance: must knowfreq 75%

basics

~20 s

Unit is Kotlin's type for functions that do useful work but return no meaningful value. It is like Java's void, but it is a real type with one value. You can leave it out of the signature.

open as a page

What does the `vararg` modifier do in a Kotlin function parameter, and how do you read its values inside the function body?

level: juniorimportance: must knowfreq 70%

basics

~10 s

vararg lets a function accept any number of arguments of one type. You call it like f(1, 2, 3) and inside the function you read them as an array you can loop over.

open as a page

When is a default argument expression evaluated — once at definition, or on each call where it is used? Show the consequences.

level: middleimportance: must knowfreq 60%

basics

~10 s

The default expression runs every time the function is called without that argument. It is not computed once and cached, so each defaulted call re-evaluates it freshly.

open as a page

What are the rules for mixing positional and named arguments in a single Kotlin call?

level: middleimportance: must knowfreq 60%

basics

~20 s

You can start a call with positional arguments and then switch to named ones, but once you use a name you generally must keep naming the rest. In modern Kotlin you may put positional arguments after named ones as long as they land in the right positions.

open as a page

Explain the difference between a bound and an unbound function reference, using `String::length` versus `"hello"::length` as examples. How do their types differ?

level: middleimportance: must knowfreq 55%

basics

~20 s

An unbound reference (String::length) leaves the object out, so you must pass it in as the first argument. A bound reference ("hello"::length) already fixes the object, so you just invoke it with no extra argument.

open as a page

When can the return type of a single-expression function be inferred, and when must you still declare it explicitly?

level: middleimportance: must knowfreq 65%

basics

~20 s

The compiler can usually figure out the return type from the expression, so you can leave it off. But for public API functions, recursive functions, or when you want a different type than what is inferred, you should write the type explicitly.

open as a page

How does the Kotlin compiler emit a top-level function on the JVM, and how is it represented in bytecode?

level: middleimportance: must knowfreq 55%

basics

~10 s

The compiler can't put free functions in bytecode, so it creates a hidden class named after the file (e.g. Utils.kt becomes UtilsKt) and makes the function a public static method on that class.

open as a page

What is the Nothing type in Kotlin, and what does it mean for a function to be declared with return type Nothing?

level: middleimportance: must knowfreq 65%

basics

~10 s

Nothing is the type for code that never returns normally — it always throws, loops forever, or stops the program. A function returning Nothing tells the compiler the line after it is unreachable.

open as a page

You already have an `Array<String>`. How do you pass it into a function whose parameter is `vararg s: String`? What is the spread operator and what exactly does it do?

level: middleimportance: must knowfreq 65%

basics

~10 s

Put a * before the array when you call the function: printAll(*myArray). The * unpacks the array so each element is passed as a separate argument instead of one array argument.

open as a page

What does @JvmOverloads do, and why is it needed when Kotlin functions with default arguments are called from Java?

level: middleimportance: should knowfreq 55%

basics

~10 s

Java does not understand Kotlin default arguments, so it sees only the full-parameter version. Adding @JvmOverloads tells the compiler to generate extra Java-visible overloads, one per defaulted parameter, so Java callers can omit them.

open as a page

Show how to factor a recursive algorithm into a local function. Why is a local function often preferred over exposing the recursive helper as a separate public/member function?

level: middleimportance: should knowfreq 45%

basics

~20 s

Put the recursive part in a function declared inside the public one. It keeps the recursion private and lets it reuse the outer parameters, so the public function's signature stays clean and the helper can't be misused from outside.

open as a page

Compare `return` behavior in a local function versus in a (non-inline and inline) lambda. What surprises candidates here?

level: middleimportance: should knowfreq 35%

basics

~20 s

In a local function, a plain return just exits that local function. In a lambda, a plain return is only allowed when the lambda is inlined, and then it exits the whole outer function. That difference trips people up.

open as a page

When would you reach for a local function instead of a lambda (or vice versa)? Give concrete decision criteria.

level: middleimportance: should knowfreq 30%

basics

~20 s

Use a local function for multi-step named helper logic, especially if it must recurse or read clearly. Use a lambda when you need to pass behavior as a value into another function, like into map or forEach.

open as a page

How do named arguments combine with default arguments to let callers skip parameters, and what's the alternative in Java interop?

level: middleimportance: should knowfreq 55%

basics

~20 s

When a function has default values, you can leave out a middle parameter by naming the later ones you want to set. Without named arguments you'd have to repeat every value up to the last one you care about.

open as a page

How do constructor references work in Kotlin, and what is their type? Give an example of using one as a factory.

level: middleimportance: should knowfreq 40%

basics

~10 s

Writing ::ClassName gives you a reference to the constructor — a function value that creates instances. You can pass it anywhere a factory function is expected, and calling it builds a new object.

open as a page

Show how if, when, and try-as-expression let you keep non-trivial logic in a single-expression function. What are the readability limits?

level: middleimportance: should knowfreq 50%

basics

~20 s

In Kotlin, if, when, and try all produce values, so you can use one of them as the single expression after the equals sign. This lets a one-line function branch or handle errors while still returning the result of that branch.

open as a page

How does Java code call a Kotlin top-level function, and what interop pitfalls should you anticipate?

level: middleimportance: should knowfreq 40%

basics

~10 s

Java calls the function as a static method on the generated file class, like FileNameKt.functionName(args). The function name and the 'Kt' suffix matter, and Kotlin-only features may not map cleanly.

open as a page

Explain how a Nothing-returning function or `throw` enables expressions like `val x = a ?: error("...")` and why the compiler then treats following code as unreachable.

level: middleimportance: should knowfreq 55%

basics

~20 s

Because a throw or a Nothing function can stand in for any type, you can put it after Elvis (?:) to get a non-null value or bail out. The compiler knows that path can't continue, so code after it is dead.

open as a page

Can you mix a spread array with individual literal arguments in a single call to a vararg function? Show what the callee receives and in what order.

level: middleimportance: should knowfreq 45%

basics

~10 s

Yes. In one call you can write individual values and spread arrays together, like f(0, *arr, 9). Kotlin combines them in the exact left-to-right order you wrote them into one array for the function.

open as a page

What are the rules for default arguments when overriding a function, and why does Kotlin forbid specifying a new default in the override?

level: seniorimportance: should knowfreq 40%

basics

~10 s

An overriding function must not declare its own default values; it inherits them from the base. This avoids ambiguity about which default applies when you call through a base-type reference.

open as a page

A local function captures and mutates a `var` from its enclosing function. Explain what the compiler does under the hood and what subtle behavior this can cause.

level: seniorimportance: should knowfreq 30%

basics

~20 s

Kotlin lets a local function change an outer var. Behind the scenes the variable is boxed in a small holder object so both the outer code and the inner function see the same value. Changes made inside are visible outside.

open as a page

Why can't you use named arguments when calling Java methods from Kotlin, and how does this interact with varargs?

level: seniorimportance: should knowfreq 45%

basics

~10 s

Java bytecode usually doesn't keep parameter names, so Kotlin can't reliably match a name to a Java method's parameter. Therefore Kotlin forbids named arguments on calls to Java methods; you must pass them positionally.

open as a page

When you write `::println`, the function is overloaded many times. How does Kotlin decide which overload the reference points to, and what happens if it's ambiguous?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Kotlin uses the surrounding context — the expected function type — to pick the matching overload. If nothing constrains the type and several overloads fit, it's ambiguous and the compiler reports an error until you add a type.

open as a page

What subtle bug can the elvis-style assignment '= ' equals sign introduce, e.g. fun f() = someBuilder.add(x)? Discuss inferred Unit and the single-expression-vs-assignment confusion.

level: seniorimportance: should knowfreq 35%

basics

~20 s

If the single expression returns nothing useful (Unit), the function silently returns Unit, which may not be what you intended. Also, beginners sometimes confuse the body equals sign with assigning a lambda, accidentally returning a function instead of calling it.

open as a page

showing 1–30 of 40