Kotlin Default Arguments
Introduction
When writing functions in programming, we often face situations where we want to provide flexibility in how a function can be called. In many languages, this requires creating multiple function versions (overloads) for different parameter combinations. Kotlin offers a simpler solution with default arguments, which allow you to specify default values for parameters, making them optional when calling the function.
In this tutorial, we'll explore Kotlin's default arguments feature, how to use it effectively, and how it helps create cleaner, more maintainable code.
The Basics of Default Arguments
What Are Default Arguments?
Default arguments are predefined values for function parameters. When a caller doesn't provide a value for a parameter with a default argument, the default value is automatically used.
Let's start with a simple example:
fun greet(name: String, greeting: String = "Hello") {
println("$greeting, $name!")
}
// Usage examples
fun main() {
greet("Alice") // Output: Hello, Alice!
greet("Bob", "Welcome") // Output: Welcome, Bob!
}
In this example, greeting
has a default value of "Hello". When we call greet("Alice")
, we're only providing the name
parameter, so the function uses the default value for greeting
.
Multiple Default Arguments
You can define multiple parameters with default values:
fun displayUserInfo(
name: String,
age: Int = 30,
isAdmin: Boolean = false,
department: String = "General"
) {
println("Name: $name")
println("Age: $age")
println("Admin: $isAdmin")
println("Department: $department")
}
fun main() {
// Using all defaults except name
println("--- User 1 ---")
displayUserInfo("John")
// Specifying some arguments
println("--- User 2 ---")
displayUserInfo("Sarah", 28, department = "Engineering")
}
Output:
--- User 1 ---
Name: John
Age: 30
Admin: false
Department: General
--- User 2 ---
Name: Sarah
Age: 28
Admin: false
Department: Engineering
Named Arguments with Default Values
Default arguments become even more powerful when combined with named arguments. This allows you to specify only the parameters you need, regardless of their order:
fun createProfile(
name: String,
email: String = "",
age: Int = 0,
isPremium: Boolean = false
) {
println("Creating profile:")
println("- Name: $name")
println("- Email: ${if (email.isNotEmpty()) email else "Not provided"}")
println("- Age: ${if (age > 0) age else "Not provided"}")
println("- Account type: ${if (isPremium) "Premium" else "Standard"}")
}
fun main() {
// Only required parameter
createProfile("Alex")
// Using named arguments to provide specific parameters
createProfile(
name = "Maria",
isPremium = true,
email = "[email protected]"
)
}
Output:
Creating profile:
- Name: Alex
- Email: Not provided
- Age: Not provided
- Account type: Standard
Creating profile:
- Name: Maria
- Email: [email protected]
- Age: Not provided
- Account type: Premium
Real-World Use Cases for Default Arguments
1. UI Component Configuration
Default arguments are great for configuring UI components:
fun createButton(
text: String,
width: Int = 100,
height: Int = 40,
isEnabled: Boolean = true,
backgroundColor: String = "#FFFFFF",
textColor: String = "#000000"
) {
println("Button created:")
println("- Text: $text")
println("- Size: ${width}x$height")
println("- Enabled: $isEnabled")
println("- BG Color: $backgroundColor")
println("- Text Color: $textColor")
}
fun main() {
// Basic button
createButton("OK")
// Custom button
createButton(
text = "Submit",
width = 200,
backgroundColor = "#0066CC",
textColor = "#FFFFFF"
)
}
2. HTTP Client Configuration
Default arguments can simplify API client configuration:
fun fetchData(
url: String,
method: String = "GET",
headers: Map<String, String> = mapOf("Content-Type" to "application/json"),
timeout: Int = 30000,
retries: Int = 3
) {
println("Fetching data from: $url")
println("- Method: $method")
println("- Headers: $headers")
println("- Timeout: $timeout ms")
println("- Retries: $retries")
// Actual implementation would go here
}
fun main() {
// Basic fetch with defaults
fetchData("https://api.example.com/data")
// POST request with custom timeout and no retries
fetchData(
url = "https://api.example.com/create",
method = "POST",
timeout = 5000,
retries = 0
)
}
3. Configuration Builder Pattern
Default arguments are useful in builder patterns:
class DatabaseConfig(
val host: String,
val port: Int,
val username: String,
val password: String,
val database: String,
val maxConnections: Int,
val timeout: Int,
val ssl: Boolean
)
fun createDatabaseConfig(
host: String = "localhost",
port: Int = 5432,
username: String = "admin",
password: String = "",
database: String,
maxConnections: Int = 10,
timeout: Int = 30000,
ssl: Boolean = false
): DatabaseConfig {
return DatabaseConfig(host, port, username, password, database, maxConnections, timeout, ssl)
}
fun main() {
// Creating minimal configuration
val defaultConfig = createDatabaseConfig(database = "app_data")
// Custom configuration
val prodConfig = createDatabaseConfig(
host = "db.production.example.com",
database = "production_data",
username = "app_service",
password = "secure_password",
ssl = true,
maxConnections = 50
)
println("Default config host: ${defaultConfig.host}")
println("Production config host: ${prodConfig.host}")
}
Default Arguments vs. Method Overloading
In many object-oriented languages like Java, method overloading is used to provide multiple versions of a function. Kotlin's default arguments offer several advantages:
- Reduced code duplication: You write one function instead of multiple overloaded versions
- More readable code: Intent is clearer with named arguments
- Easier maintenance: Changes only need to be made in one place
Consider this comparison:
Java-style Overloading:
// Java-style overloading
fun connect(host: String, port: Int, username: String, password: String, database: String) {
// Implementation with all parameters
}
fun connect(host: String, port: Int, username: String, password: String) {
connect(host, port, username, password, "default_db")
}
fun connect(host: String, port: Int, username: String) {
connect(host, port, username, "", "default_db")
}
fun connect(host: String, port: Int) {
connect(host, port, "admin", "", "default_db")
}
fun connect(host: String) {
connect(host, 5432, "admin", "", "default_db")
}
Kotlin Default Arguments:
fun connect(
host: String,
port: Int = 5432,
username: String = "admin",
password: String = "",
database: String = "default_db"
) {
println("Connecting to $database on $host:$port as $username")
// Implementation with all parameters
}
fun main() {
connect("db.example.com")
connect("db.example.com", 3306)
connect("db.example.com", 3306, "user")
connect("db.example.com", username = "user", database = "custom_db")
}
The Kotlin version is much more concise and maintainable!
Important Considerations
1. Default Arguments are Evaluated at Call Time
Default values are computed during the function call, not during function definition:
var counter = 0
fun incrementingDefault(value: Int = counter++) {
println("value = $value, counter = $counter")
}
fun main() {
incrementingDefault() // value = 0, counter = 1
incrementingDefault() // value = 1, counter = 2
incrementingDefault() // value = 2, counter = 3
}
2. Default Arguments and Java Interoperability
When calling Kotlin functions with default arguments from Java, you must provide all arguments, as Java doesn't understand Kotlin's default arguments. To solve this, use the @JvmOverloads
annotation:
@JvmOverloads
fun formatName(
firstName: String,
lastName: String,
middleName: String = "",
title: String = ""
): String {
val fullName = buildString {
if (title.isNotEmpty()) append("$title ")
append(firstName)
if (middleName.isNotEmpty()) append(" $middleName")
append(" $lastName")
}
return fullName
}
This generates Java-friendly overloaded methods.
Summary
Kotlin's default arguments feature offers significant advantages for writing clean, flexible, and maintainable code:
- Reduces the need for function overloading
- Makes code more readable with named arguments
- Provides sensible defaults while allowing customization
- Simplifies API design and usage
- Works well with Kotlin's other features like named arguments
As you continue developing in Kotlin, default arguments will become one of your favorite features for creating flexible and user-friendly APIs.
Exercises
To practice using default arguments in Kotlin:
-
Create a function
calculatePrice
that computes the final price of a product with parameters for base price, tax rate (default 0.1), discount (default 0), and shipping (default 5.99). -
Write a function to create formatted text with parameters for text content, font size (default 12), color (default "black"), and style options like bold and italic (default false).
-
Implement a logging function with parameters for message, level (default "INFO"), timestamp (default current time), and tags (default empty list).
Additional Resources
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)