Skip to main content

Kotlin Expression Bodies

Introduction

In Kotlin, functions and properties can be defined in a concise way using expression bodies. An expression body is a compact syntax that allows you to define a function or property that returns the value of a single expression without using curly braces and an explicit return statement. This feature contributes to Kotlin's goal of being more expressive and concise than many other programming languages.

Expression bodies are particularly useful when you want to create simple functions that compute and return a value without complex logic. This lesson will help you understand how to use expression bodies effectively in your Kotlin programs.

Basic Syntax

Let's first look at a regular function with a traditional body:

kotlin
fun sum(a: Int, b: Int): Int {
return a + b
}

The same function can be rewritten using an expression body:

kotlin
fun sum(a: Int, b: Int): Int = a + b

Notice the key differences:

  • The curly braces {} are gone
  • The return keyword is removed
  • The = symbol replaces the opening brace
  • The function body consists of a single expression

Type Inference with Expression Bodies

When using expression bodies, Kotlin can often infer the return type, allowing you to omit it:

kotlin
fun sum(a: Int, b: Int) = a + b

The compiler knows that a + b results in an Int, so specifying the return type is optional. However, for clarity and documentation purposes, it's often a good practice to include return types in function signatures.

Examples of Expression Bodies

Simple Calculations

kotlin
fun multiply(a: Int, b: Int) = a * b
fun divide(a: Double, b: Double) = a / b

fun main() {
println("4 * 5 = ${multiply(4, 5)}")
println("10.0 / 2.5 = ${divide(10.0, 2.5)}")
}

Output:

4 * 5 = 20
10.0 / 2.5 = 4.0

String Operations

kotlin
fun greet(name: String) = "Hello, $name!"
fun getInitials(fullName: String) = fullName.split(" ")
.map { it.first().toUpperCase() }
.joinToString("")

fun main() {
println(greet("Kotlin Developer"))
println("Initials of 'John Doe': ${getInitials("John Doe")}")
}

Output:

Hello, Kotlin Developer!
Initials of 'John Doe': JD

Conditional Logic

Expression bodies can also contain conditional expressions:

kotlin
fun max(a: Int, b: Int) = if (a > b) a else b

fun temperatureDescription(celsius: Double) = when {
celsius < 0 -> "Freezing"
celsius < 10 -> "Cold"
celsius < 20 -> "Cool"
celsius < 30 -> "Warm"
else -> "Hot"
}

fun main() {
println("Max of 7 and 12: ${max(7, 12)}")
println("23.5°C is ${temperatureDescription(23.5)}")
}

Output:

Max of 7 and 12: 12
23.5°C is Warm

Expression Bodies for Properties

Expression bodies aren't limited to functions. They can also be used with properties:

kotlin
class Rectangle(val width: Int, val height: Int) {
val area = width * height
val perimeter = 2 * (width + height)
val isSquare = width == height
}

fun main() {
val rect = Rectangle(5, 10)
println("Area: ${rect.area}")
println("Perimeter: ${rect.perimeter}")
println("Is square: ${rect.isSquare}")
}

Output:

Area: 50
Perimeter: 30
Is square: false

When to Use Expression Bodies

Expression bodies are ideal when:

  1. A function returns a single expression
  2. The function logic is simple and can be expressed in one line
  3. You want to make your code more concise and readable

However, not all functions should use expression bodies. When your function contains multiple statements, requires complex logic, or has side effects beyond returning a value, a traditional function body with curly braces is more appropriate.

Real-World Applications

UI Event Handlers

kotlin
// In Android development
button.setOnClickListener { view -> navigateToNextScreen() }

// The navigateToNextScreen function could be defined as:
fun navigateToNextScreen() = findNavController().navigate(R.id.action_current_to_next)

Data Transformation in a Chain

kotlin
fun getUserFullNames(users: List<User>) = users
.filter { it.isActive }
.map { "${it.firstName} ${it.lastName}" }

// In a real application
fun main() {
val users = listOf(
User("John", "Doe", true),
User("Jane", "Smith", false),
User("Bob", "Johnson", true)
)

val activeUserNames = getUserFullNames(users)
println("Active users: $activeUserNames")
}

data class User(val firstName: String, val lastName: String, val isActive: Boolean)

Output:

Active users: [John Doe, Bob Johnson]

Configuration Functions

kotlin
fun defaultSettings() = Settings(
darkMode = true,
fontSize = 14,
language = "English"
)

data class Settings(val darkMode: Boolean, val fontSize: Int, val language: String)

fun main() {
val settings = defaultSettings()
println("Default settings: $settings")
}

Output:

Default settings: Settings(darkMode=true, fontSize=14, language=English)

Common Pitfalls and Best Practices

Be Careful with Side Effects

Although technically possible, it's not considered good practice to include functions with side effects in expression bodies:

kotlin
// Not recommended
fun printAndReturn(message: String) = println(message).also { "Message printed" }

// Better approach
fun printAndReturn(message: String): String {
println(message)
return "Message printed"
}

Keep It Simple

Expression bodies should be simple and readable. If the expression is too complex, consider using a regular function body:

kotlin
// Too complex for an expression body
fun calculateComplexFormula(x: Double, y: Double) =
Math.pow(x, 2.0) * Math.sin(y) + Math.sqrt(Math.abs(x * y)) / (1 + Math.exp(x - y))

// Better as a regular function
fun calculateComplexFormula(x: Double, y: Double): Double {
val term1 = Math.pow(x, 2.0) * Math.sin(y)
val term2 = Math.sqrt(Math.abs(x * y))
val term3 = 1 + Math.exp(x - y)

return term1 + term2 / term3
}

Consider Readability

Always prioritize readability over conciseness:

kotlin
// Technically correct but harder to understand
fun isEligible(user: User) = user.age >= 18 && user.hasValidId && (!user.isBanned || user.hasSpecialPermission)

// More readable
fun isEligible(user: User): Boolean {
if (user.isBanned && !user.hasSpecialPermission) {
return false
}

return user.age >= 18 && user.hasValidId
}

Summary

Kotlin expression bodies are a powerful feature that allows you to write more concise and expressive code. By replacing traditional function bodies with a single expression, you can make your code more readable for simple operations.

Key points to remember:

  • Expression bodies use the = symbol instead of curly braces
  • They're ideal for simple functions that return a single expression
  • The return type can often be inferred by the compiler
  • They can be used for both functions and properties
  • They work well with conditional expressions like if and when
  • Always prioritize readability over extreme conciseness

Exercises

  1. Convert the following function to use an expression body:

    kotlin
    fun isEven(number: Int): Boolean {
    return number % 2 == 0
    }
  2. Write a function with an expression body that returns the absolute value of a number.

  3. Create a function that converts a temperature from Fahrenheit to Celsius using an expression body.

  4. Implement a Person class with properties for firstName and lastName, and add a property fullName with an expression body.

  5. Write a function that checks if a string is a palindrome (reads the same backward as forward) using an expression body.

Additional Resources



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)