Default & Named Arguments
Reviewed & published by Brayan K
Kotlin is a modern, concise language that lets functions declare default parameter values and lets callers pass arguments by name — together they replace the tangle of overloaded methods found in other languages.
Part of the free Kotlin course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
By the end of this lesson you'll write flexible functions with defaults and call them with clear, self-documenting named arguments.
What You'll Learn in This Lesson
- How to give parameters default values
- How defaults remove the need for overloads
- How to pass arguments by name
- Skipping earlier defaults to set a later parameter
- Mixing positional and named arguments correctly
- When defaults are evaluated
1️⃣ Default Argument Values
A parameter can declare a default with =. If the caller omits that argument, the default is used. This means one function definition can serve many call patterns — no overloading required.
// Give parameters default values with '='. Callers can omit them.
fun greet(name: String, greeting: String = "Hello", excited: Boolean = false): String {
val mark = if (excited) "!" else "."
return "$greeting, $name$mark"
}
fun main() {
println(greet("Ada")) // both defaults used
println(greet("Ada", "Hi")) // override greeting only
println(greet("Ada", "Hey", true)) // override all
}A single greet function handled three different call styles. In Java this would have meant three separate overloaded methods.
2️⃣ Named Arguments
When calling a function you can label each argument with its parameter name. This makes calls self-documenting, lets you reorder arguments, and — crucially — lets you skip earlier defaulted parameters to set just a later one.
fun makeBox(width: Int = 1, height: Int = 1, depth: Int = 1): String =
"Box ${width}x${height}x$depth"
fun main() {
// Named arguments make calls self-documenting AND let you skip
// earlier defaults to set a later one.
println(makeBox(width = 4, depth = 2)) // height stays 1
println(makeBox(height = 10)) // only height set
println(makeBox(2, 3, 4)) // positional still works
// Named args can come in any order:
println(makeBox(depth = 5, width = 5, height = 5))
}makeBox(height = 10) sets only the height and leaves width and depth at their defaults — impossible with purely positional calls.
Your turn. Replace the TODO, then run and compare.
// 🎯 YOUR TURN — replace each TODO then run main()
// A function with two defaulted parameters.
fun coffee(size: String = "medium", shots: Int = 1): String =
"$size coffee with $shots shot(s)"
fun main() {
// 1) Call with all defaults
println(coffee()) // expect: medium coffee with 1 shot(s)
// 2) Use a NAMED argument to set ONLY shots to 2
println(coffee(TODO = 2)) // 👉 replace TODO with 'shots'
// 3) Override the size positionally
println(coffee("large")) // expect: large coffee with 1 shot(s)
// ✅ Expected line 2: medium coffee with 2 shot(s)
}Mini-Challenge: A Flexible Logger
Write one log function with two defaulted parameters, then call it three different ways using named arguments.
// 🎯 MINI-CHALLENGE: a flexible logger.
// Save as Logger.kt and run main().
//
// 1. Write fun log(message: String, level: String = "INFO",
// uppercase: Boolean = false): String
// that returns "[<level>] <message>" and applies .uppercase()
// to the message when uppercase is true.
// 2. In main(), call it three ways:
// - just a message
// - with level = "ERROR" (named)
// - with uppercase = true (named)
//
// ✅ Example output:
// [INFO] starting up
// [ERROR] disk full
// [INFO] DONE
fun main() {
// your code here
}Common Errors (and the fix)
- "Mixing named and positional arguments is not allowed" — Once you use a named argument, all following arguments must also be named. Put positional ones first.
- "No value passed for parameter" — A parameter without a default was omitted. Either pass it or give it a default value.
- Wrong parameter name — A typo in a named argument (colour = ... vs color = ...) won't compile. Match the declared name exactly.
- Expecting Java to see defaults — Java callers don't see Kotlin defaults unless you add @JvmOverloads. Within Kotlin it just works.
Pro Tips
- 💡 Name boolean arguments: connect(secure = true) reads far better than connect(true).
- 💡 Defaults can use earlier params: a later default may reference an earlier parameter's value.
- 💡 Order defaults thoughtfully: put the most-often-overridden parameters earlier so positional calls stay natural.
📋 Quick Reference — Arguments
| Concept | Kotlin Syntax |
|---|---|
| Default value | fun f(x: Int = 1) |
| Call with default | f() |
| Named argument | f(x = 5) |
| Skip earlier default | makeBox(depth = 2) |
| Java interop | @JvmOverloads |
🎉 Lesson Complete!
- ✅ Default values let callers omit arguments
- ✅ One function with defaults replaces many overloads
- ✅ Named arguments make calls self-documenting
- ✅ Named arguments let you skip earlier defaults
- ✅ Positional arguments must come before named ones
Practice quiz
How do you give a Kotlin function parameter a default value?
- With the default keyword
- With a ? after the name
- With = after the type, e.g. greeting: String = "Hello"
- Defaults are not supported
Answer: With = after the type, e.g. greeting: String = "Hello". A parameter declares a default with =, used when the caller omits it.
What is a key benefit of default arguments?
- One function definition can replace many overloads
- They make functions run faster
- They prevent null values
- They are required on every parameter
Answer: One function definition can replace many overloads. Defaults let one function serve many call patterns without overloading.
What does a named argument let you do that positional args cannot?
- Call a private function
- Change a parameter's type
- Add new parameters at runtime
- Skip earlier defaulted parameters to set only a later one
Answer: Skip earlier defaulted parameters to set only a later one. Named args can skip earlier defaults, e.g. makeBox(depth = 2).
Can you reorder arguments in a call using named arguments?
- No, order is always fixed
- Yes, named arguments can appear in any order
- Only the first two
- Only if all are named
Answer: Yes, named arguments can appear in any order. Named arguments may come in any order.
Mixing positional and named arguments: which rule applies?
- Once an argument is named, all following ones must also be named
- Named must come first
- You can never mix them
- Positional must come last
Answer: Once an argument is named, all following ones must also be named. f(1, y = 2) is fine, but f(x = 1, 2) is not.
When are default argument values evaluated?
- Once at definition time
- Never, they are constants
- On each call where the argument is omitted
- Only the first time the function runs
Answer: On each call where the argument is omitted. Defaults are evaluated per call, so System.currentTimeMillis() gives a fresh value each time.
What happens if you type a wrong parameter name in a named argument?
- It is silently ignored
- It won't compile
- It uses the default
- It picks the closest match
Answer: It won't compile. The named argument must match a declared parameter name exactly.
What does greet("Ada") output if greeting defaults to "Hello" and excited to false?
- Hello, Ada!
- Ada
- Hi, Ada.
- Hello, Ada.
Answer: Hello, Ada.. Both defaults are used: greeting Hello and excited false gives a period.
Why do Java callers not see Kotlin default arguments automatically?
- Java cannot call Kotlin
- Java needs @JvmOverloads to generate overloads
- Defaults are private
- Java ignores all annotations
Answer: Java needs @JvmOverloads to generate overloads. Within Kotlin defaults just work; Java interop needs @JvmOverloads.
Can a default value reference an earlier parameter of the same function?
- No, never
- Only constants are allowed
- Yes, a later default may use an earlier parameter
- Only the first parameter
Answer: Yes, a later default may use an earlier parameter. Defaults can reference earlier parameters of the same function.
Continue this course
- Previous: Functions
- Next: Collections (List, Set, Map) — Store groups of data with read-only and mutable collections
- Quick reference: Kotlin cheat sheet › Functions & Lambdas
Frequently asked questions
How do default arguments reduce the need for overloads?
In languages without default values you often write several overloaded versions of the same function — one with two parameters, one with three, one with four — just to allow optional inputs. Kotlin lets a single function declare defaults like greeting: String = "Hello", so one definition covers all those cases. Callers supply only the arguments they care about, and the rest fall back to their defaults.
When should I use named arguments?
Named arguments shine in three situations: when a call has several parameters of the same type and positional order is easy to get wrong; when you want the call site to be self-documenting (makeBox(width = 4) is clearer than makeBox(4)); and when you want to skip over earlier default parameters to set a later one. They also let you reorder arguments freely.
Can I mix positional and named arguments in one call?
Yes, but with a rule: once you start using named arguments in a call, every argument after the first named one must also be named. So f(1, y = 2) is fine, but f(x = 1, 2) is not. In practice, pass any leading positional arguments first, then switch to named arguments for the rest.
Are default argument values evaluated once or on every call?
Default values are evaluated on each call where the argument is omitted, not once at definition time. This means a default like createdAt: Long = System.currentTimeMillis() produces a fresh value every time the function is called without that argument. Defaults can also reference earlier parameters of the same function.