Hello! Welcome to the fifth lesson in our "Kotlin Fundamentals" module.
In our last lesson, we mastered iteration using for, while, and do-while loops, paying close attention to Kotlin's expressive ranges. We now have a solid grip on controlling the flow of our programs.
Today, we'll shift our focus to making our code more modular, readable, and flexible by exploring advanced function features. This lesson covers default parameter values and named arguments. You'll learn how these features allow you to write functions that are easier to call and understand, a significant improvement over the function overloading patterns you might be used to from Java.
By the end of this lesson, you will be able to define and call functions with default parameter values and named arguments, a skill that is heavily used in modern Kotlin development, especially in Jetpack Compose.
The Problem with Function Overloading
In Java, if you want a function to have optional parameters, you typically need to create multiple versions of that function, each with a different set of parameters. This is called function overloading. While it works, it can lead to a lot of boilerplate code, especially when you have several optional parameters.
Let's watch a short video that frames this problem and introduces how Kotlin's default arguments provide a much cleaner solution.
Kotlin for Beginners - Part 19 - DEFAULT & NAMED ARGUMENTS
The video 'DEFAULT & NAMED ARGUMENTS' from Coding in Flow effectively explains the issue with function overloading that you've likely encountered in Java and sets the stage for Kotlin's more elegant approach.
Watch the first 3 minutes and 11 seconds (00:00 - 03:11). Pay attention to the comparison between creating multiple overloaded functions and the cleaner alternative that default parameters will offer.
Default Arguments: Write Less, Do More
As the video highlighted, maintaining multiple function overloads is not ideal. Kotlin solves this with default arguments. You can assign a default value to a function's parameter directly in its signature. If a caller omits that argument, the default value is used automatically.
Defining Default Arguments
The syntax is straightforward: you add = followed by the default value after the parameter's type.
Let's look at a practical example from another tutorial.
#19 Kotlin Tutorial | Default and Named Parameters
This clip from Telusko's tutorial provides a clear, step-by-step example of defining a function with a default parameter and calling it both with and without the optional argument.
Watch from 04:06 to 07:52. Notice how the interest parameter is given a default value, making it optional when calling the calcAmount function. The video also correctly notes that Kotlin's basic types like Int and Double start with a capital letter, unlike Java's primitives.
Here is a summary of the concept shown in the video:
// The 'interest' parameter has a default value of 0.04
fun calcAmount(amount: Double, interest: Double = 0.04): Double {
return amount * (1 + interest)
}
// You can call it by providing only the required parameters.
// 'interest' will default to 0.04
val totalAmountDefault = calcAmount(50.0) // Returns 52.0
// Or, you can override the default by providing a value.
val totalAmountCustom = calcAmount(50.0, 0.03) // Returns 51.5
This single function achieves what would have required two separate functions in Java.

Named Arguments: Clarity and Flexibility
Default arguments are powerful, but what if you have multiple optional parameters and you only want to specify the last one, skipping the ones in the middle? This is where named arguments come in.
When you call a function, you can explicitly name the parameters you're providing values for. This offers two major benefits:
- Readability: The function call becomes self-documenting.
resize(width = 100, height = 50)is much clearer thanresize(100, 50). - Flexibility: You can provide arguments in any order, and you can easily skip optional parameters.
Let's see how this works in practice.
Quick Guide to Kotlin Default and Named Arguments
The article 'Quick Guide to Kotlin Default and Named Arguments' from Baeldung provides excellent, clear-cut examples of why named arguments are useful and how to use them.
Read sections 2 ('Positional Arguments') and 3 ('Kotlin’s Named Arguments'). Focus on how named arguments solve the readability problem of positional arguments and the rules for mixing them.
Combining Default and Named Arguments
The true power of these features is revealed when you use them together. Let's revisit the problem of skipping a middle parameter.
Consider this function from the Baeldung article:
fun connect(url: String, connectTimeout: Int = 1000, enableRetry: Boolean = true) { /* ... */ }
If you want to provide a url and specify enableRetry but use the default connectTimeout, you must use a named argument:
// This will cause a compiler error because 'false' doesn't match the second parameter's type (Int).
// connect("http://example.com", false)
// This is the correct way, using a named argument to skip the middle parameter.
connect("http://example.com", enableRetry = false)
This combination is fundamental to writing idiomatic Kotlin, and you will see it everywhere in Android development with Jetpack Compose.
Connection to Jetpack Compose
Your goal is to build Android UIs with Jetpack Compose. Compose APIs rely heavily on default and named arguments to make UI components both simple to use and highly customizable.
Let's look at an official explanation.
This official Android Developers guide explains exactly why default arguments are so important for Compose. The example using the Text composable is perfect.
Read the section 'Default arguments'. Notice how a simple call to Text(text = "Hello") is made possible because dozens of other parameters for styling and layout have default values.
As the guide shows, a simple Text("Hello, Android!") is equivalent to a much longer call where every parameter is specified. Thanks to default arguments, you only need to care about the parameters you want to change. And thanks to named arguments, you can change them clearly and without worrying about their order. For example: Text(text = "Error", color = Color.Red).
Advanced Considerations
There are a couple of important rules to be aware of when working with these features.
Overriding Functions
When you override a function from a parent class or interface, you cannot change the default parameter values. The default values from the base function are always used.
Quick Guide to Kotlin Default and Named Arguments
Let's return to the Baeldung article to understand how default arguments behave with inheritance.
Read section 5, 'Overriding Functions and Default Arguments'. The key takeaway is that an overriding function inherits the default values and cannot specify its own.
Java Interoperability with @JvmOverloads
Since you have a background in Java, you might wonder how these Kotlin functions with default parameters can be called from Java code. By default, Java sees only the full function signature. To expose the convenient "overloaded" versions to Java, you can use the @JvmOverloads annotation.
#19 Kotlin Tutorial | Default and Named Parameters
The Telusko video we watched earlier has a great segment explaining @JvmOverloads. This is a very practical tip for anyone working in a mixed Java/Kotlin codebase, which is common in established Android projects.
Watch from 07:41 to 10:09. Observe how adding @JvmOverloads to the Kotlin function automatically generates the overloaded methods for the Java caller.
Practice
Let's apply these concepts to your e-commerce and recipe book projects.
Imagine you're creating a function to display a product listing in your FAB e-commerce app. A product always has a name and a price, but showing a discount or a "new" badge is optional.
-
Define a function
displayProductwith the following parameters:name: String(required)price: Double(required)discountPercentage: Double(optional, default is0.0)isNew: Boolean(optional, default isfalse)
-
Inside the function, print out the details. You can use an
ifstatement to decide whether to show the discount or "NEW!" badge. -
In your
mainfunction, calldisplayProductin the following ways:- For a standard product: "Classic T-Shirt", price 25.50.
- For a new product: "Wireless Headphones", price 199.99. Use a named argument to set
isNewtotrue. - For a product on sale: "Coffee Maker", price 80.0, with a 15% discount (
0.15).
Click for the solution
fun displayProduct(
name: String,
price: Double,
discountPercentage: Double = 0.0,
isNew: Boolean = false
) {
var finalPrice = price * (1 - discountPercentage)
print("Product: $name, Price: $${"%.2f".format(finalPrice)}")
if (discountPercentage > 0.0) {
print(" (${(discountPercentage * 100).toInt()}% off!)")
}
if (isNew) {
print(" [NEW!]")
}
println() // For a new line
}
fun main() {
// 1. Standard product (uses all defaults)
displayProduct("Classic T-Shirt", 25.50)
// 2. New product (uses named argument to skip 'discountPercentage')
displayProduct(name = "Wireless Headphones", price = 199.99, isNew = true)
// 3. Product on sale
displayProduct(name = "Coffee Maker", price = 80.0, discountPercentage = 0.15)
}
// Expected Output:
// Product: Classic T-Shirt, Price: $25.50
// Product: Wireless Headphones, Price: $199.99 [NEW!]
// Product: Coffee Maker, Price: $68.00 (15% off!)
This solution demonstrates how a single, flexible function can handle multiple scenarios cleanly, avoiding the need for several overloaded methods.
Key Takeaways
- Default Arguments allow you to specify fallback values for function parameters, reducing the need for function overloading.
- Named Arguments improve code readability and give you the flexibility to pass arguments in any order and skip optional ones.
- These two features are most powerful when used together, enabling the creation of highly flexible and self-documenting APIs, a pattern used extensively in Jetpack Compose.
- When overriding functions, you cannot redefine default parameter values; they are inherited from the base function.
- Use the
@JvmOverloadsannotation to expose user-friendly overloaded functions to Java code.
Next Steps
We've just seen how to make function calls more concise and readable. In the next lesson, we'll look at how to make the function definitions themselves more concise with single-expression functions, another of Kotlin's elegant syntactic features.