Kotlin Functions: Parameters, Default/Named Arguments, Vararg, Single Expression & Local Functions
1. Defining Functions and Parameters
How do you define functions and parameters in Kotlin?
Functions in Kotlin are defined using the fun keyword, with optional parameters and return types. Parameters are typed values passed to functions, requiring explicit type annotations unless inferred. Return types are optional if inferred and use Unit for void equivalents.
Syntax:
fun functionName(param1: Type1, param2: Type2): ReturnType {
// Function body
return value
}
Use Case: Encapsulating reusable logic (e.g., calculations).
Example:
// Defining and calling functions
fun greet(name: String): String {
return "Hello, $name!"
}
fun calculateSum(a: Int, b: Int): Int {
return a + b
}
// Calling functions
fun main() {
val message = greet("Krishna")
println(message)
val sum = calculateSum(5, 3)
println("Sum: $sum")
}
Hello, Krishna!
Sum: 8
Note: greet returns a string using string interpolation ($name). calculateSum demonstrates typed parameters and return type. Run with: kotlinc basic_functions.kt -include-runtime -d basic_functions.jar && java -jar basic_functions.jar.
2. Default and Named Arguments
What are default and named arguments in Kotlin?
Default Arguments: Parameters with predefined values, making them optional during calls. Syntax: fun func(param: Type = defaultValue).
Named Arguments: Parameters passed by name, allowing flexible order and skipping defaults. Syntax: func(param1 = value1, param2 = value2).
Use Case: Simplifying function calls for optional parameters (e.g., configuration functions).
Example:
// Default and named arguments
fun calculateBonus(salary: Int, rate: Double = 0.1, bonusType: String = "Standard"): Double {
val bonusRate = if (bonusType == "Premium") rate * 1.5 else rate
return salary * bonusRate
}
fun main() {
// Using defaults
val standardBonus = calculateBonus(50000)
println("Standard bonus: $standardBonus")
// Named arguments (out of order)
val premiumBonus = calculateBonus(salary = 60000, bonusType = "Premium")
println("Premium bonus: $premiumBonus")
// Mixing named and positional
val customBonus = calculateBonus(55000, bonusType = "Standard")
println("Custom bonus: $customBonus")
}
Standard bonus: 5000.0
Premium bonus: 9000.0
Custom bonus: 5500.0
Note: rate defaults to 0.1; bonusType to "Standard". Named arguments allow skipping or reordering.
3. Single Expression Functions
What are single expression functions in Kotlin?
Single expression functions are concise functions with a single expression as the body, using = instead of curly braces and return. The expression's value is returned automatically.
Syntax: fun func(param: Type): ReturnType = expression.
Use Case: Concise functions for simple calculations or transformations.
Example:
// Single expression functions
fun square(x: Int): Int = x * x
fun isEven(num: Int): Boolean = num % 2 == 0
fun greet(name: String, greeting: String = "Hello") = "$greeting, $name!"
fun main() {
println("Square of 5: ${square(5)}")
println("Is 4 even? ${isEven(4)}")
println(greet("Krishna"))
println(greet("Ram", "Hi"))
}
Square of 5: 25
Is 4 even: true
Hello, Krishna!
Hi, Ram!
Note: square and isEven return the expression's result directly. greet combines default and single-expression syntax.
4. Variable Number of Arguments (vararg)
What are variable number of arguments (vararg) in Kotlin?
vararg allows a function to accept a variable number of arguments, treated as an array. Arguments can be passed individually or unpacked from arrays using the spread operator (*).
Syntax: fun func(vararg args: Type).
Use Case: Functions with dynamic argument counts (e.g., sum, logging).
Example:
// Variable number of arguments (vararg)
fun sum(vararg numbers: Int): Int {
var total = 0
for (num in numbers) {
total += num
}
return total
}
fun printMessages(vararg messages: String) {
for (msg in messages) {
println(msg)
}
}
fun main() {
println("Sum: ${sum(1, 2, 3, 4)}")
println("Sum with array: ${sum(*arrayOf(5, 6, 7))}")
printMessages("Hello", "World", "Kotlin")
}
Sum: 10
Sum with array: 18
Hello
World
Kotlin
Note: sum sums variable integers; *arrayOf spreads an array into arguments. printMessages prints variable strings.
5. Local Functions
What are local functions in Kotlin?
Local functions are functions defined inside another function, with access to the outer function's scope. They help encapsulate helper logic without polluting the global namespace.
Syntax:
fun outerFunction(param: Type) {
fun localFunction(): ReturnType {
// Can access param
return param * 2
}
return localFunction()
}
Use Case: Helper functions for specific outer function logic.
Example:
// Local functions example
fun processData(input: Int): Int {
fun validate(num: Int): Boolean {
return num > 0
}
fun calculate(num: Int): Int {
if (!validate(num)) {
return 0
}
return num * 2 // Uses input from outer scope
}
return calculate(input)
}
fun main() {
println("Processed: ${processData(5)}") // 10
println("Processed: ${processData(0)}") // 0
}
Processed: 10
Processed: 0
Note: validate and calculate are local to processData. calculate accesses input from the outer scope.
6. Comprehensive Example Combining All Function Concepts
Example:
// Comprehensive Kotlin functions example
fun processEmployee(name: String, salary: Double = 50000.0, vararg skills: String, dept: String = "IT", role: String = "Developer"): String {
// Local function
fun calculateBonus(years: Int): Double {
return if (years >= 5) salary * 0.1 else salary * 0.05
}
// Single expression function
val totalSalary = { years: Int -> salary + calculateBonus(years) }
val bonus = calculateBonus(6)
val total = totalSalary(6)
return """
Employee: $name
Department: $dept
Role: $role
Skills: ${skills.joinToString()}
Bonus: $${bonus}
Total Salary: $${total}
""".trimIndent()
}
fun main() {
// Default arguments
val result1 = processEmployee("Krishna")
println(result1)
// Named arguments
val result2 = processEmployee("Ram", dept = "HR", role = "Manager")
println(result2)
// Vararg
val result3 = processEmployee("Kristal", 60000.0, "Kotlin", "Java", "SQL", dept = "DevOps")
println(result3)
}
Employee: Krishna
Department: IT
Role: Developer
Skills:
Bonus: $5000.0
Total Salary: $55000.0
Employee: Ram
Department: HR
Role: Manager
Skills:
Bonus: $5000.0
Total Salary: $55000.0
Employee: Kristal
Department: DevOps
Role: Developer
Skills: Kotlin, Java, SQL
Bonus: $6000.0
Total Salary: $66000.0
Description: processEmployee uses various argument types. Default/Named: salary, dept, role defaults; named for flexibility. Vararg: skills accepts variable strings. Local Function: calculateBonus for bonus calculation. Single Expression: totalSalary lambda. Uses string interpolation and joinToString for output.
7. Common Mistakes and Best Practices
Common Mistakes:
- Defining/Parameters: Forgetting type annotations for parameters or return types. Not handling nullable parameters, causing NullPointerException.
- Default/Named Arguments: Overriding defaults incorrectly in inheritance. Forgetting named arguments for optional parameters.
- Single Expression: Using complex expressions that reduce readability. Forgetting that single-expression functions still need types.
- Vararg: Passing arrays without
*spread operator. Overusing vararg for large inputs, impacting performance. - Local Functions: Accessing outer scope variables incorrectly. Over-nesting local functions, complicating debugging.
- General: Not documenting functions with KDoc. Ignoring exception handling in functions.
Best Practices:
- Defining/Parameters: Specify types for parameters and return values for clarity. Use nullable types (
String?) when appropriate. - Default/Named Arguments: Provide meaningful defaults to simplify calls. Use named arguments for clarity in complex signatures.
- Single Expression: Use for simple logic to improve readability. Ensure expressions are concise and self-documenting.
- Vararg: Use
*to spread arrays into vararg parameters. Limit vararg usage to small, known argument counts. - Local Functions: Use for helper logic specific to the outer function. Keep local functions simple to avoid nesting complexity.
- General: Follow Kotlin coding conventions (e.g., camelCase for functions). Document with KDoc (
/** */). Test functions with edge cases (e.g., null inputs, empty vararg). UseUnitexplicitly for void returns if needed.