Question

Return Multiple Values from a Kotlin Function

Question

How can a Kotlin function return three separate Int values—hour, minute, and second—in a single call, similar to a Swift function that returns (Int, Int, Int)?

func getTime() -> (Int, Int, Int) {
    return (hour, minute, second)
}

Is there a Kotlin equivalent for returning multiple values without using an array or a map?

Short Answer

Kotlin functions return one value, but that value can be an object containing several values. For a fixed set of named values such as hour, minute, and second, a data class is usually the clearest solution. Kotlin also provides Pair and Triple for small, temporary groups of values, and supports destructuring to unpack them conveniently.

Concept

A Kotlin function has one return type. However, that return value may be an object that contains multiple pieces of data.

Swift supports tuple types such as (Int, Int, Int) directly. Kotlin does not provide general-purpose tuple types with arbitrary numbers of elements. Instead, Kotlin offers:

  • Pair<A, B> for exactly two values.
  • Triple<A, B, C> for exactly three values.
  • A custom data class for named, meaningful values.

For time components, a data class is usually preferable because names make the result self-documenting:

data class TimeParts(
    val hour: Int,
    val minute: Int,
    val second: Int
)

A caller can immediately see what each value means. In contrast, Triple<Int, Int, Int> exposes values as first, second, and third, which can be easy to mix up.

This matters in real programs because return values become part of your function's API. Clear names reduce bugs and make code easier to read, change, test, and maintain.

Mental Model

Think of a function's return value as one package it can hand back to its caller.

  • A single Int is a package containing one item.
  • A Triple<Int, Int, Int> is a package containing three numbered compartments.
  • A TimeParts data class is a package with compartments clearly labelled hour, minute, and second.

All three values travel back from the function together, but Kotlin treats the package itself as the one returned value.

Take Quiz

Syntax and Examples

Use a data class when the values have specific meanings.

data class TimeParts(
    val hour: Int,
    val minute: Int,
    val second: Int
)

fun getTime(): TimeParts {
    return TimeParts(hour = 14, minute = 30, second = 45)
}

fun main() {
    val time = getTime()

    println(time.hour)   // 14
    println(time.minute) // 30
    println(time.second) // 45
}

The function returns one TimeParts object. That object stores the three Int values as named properties.

Kotlin also supports destructuring declarations for data classes:

val (hour, minute, second) = getTime()

println("$hour:$minute:$second") // 14:30:45

A data class automatically provides component functions for its constructor properties, allowing the destructuring syntax above.

For a quick, less descriptive option, use Triple:

fun getTime(): Triple<Int, Int, Int> {
    return Triple(14, 30, 45)
}

val (hour, minute, second) = getTime()

Triple works, but use a data class when the returned values represent a real concept such as a time, coordinate, result, or validation outcome.

Step by Step Execution

Consider this code:

data class TimeParts(val hour: Int, val minute: Int, val second: Int)

fun getTime(): TimeParts {
    return TimeParts(9, 5, 12)
}

fun main() {
    val (hour, minute, second) = getTime()
    println("$hour:$minute:$second")
}

Execution proceeds as follows:

  1. TimeParts defines an object with three Int properties.
  2. main calls getTime().
  3. getTime() creates TimeParts(9, 5, 12).
  4. That one TimeParts object is returned to main.
  5. The destructuring declaration calls the data class's generated component functions:
    • hour receives 9
    • minute receives 5
    • second receives 12
  6. The program prints:
9:5:12

If you wrote val time = getTime() instead, you would access the same values through time.hour, time.minute, and time.second.

Real World Use Cases

Returning a small value object is common when a calculation naturally produces related results:

  • Parsing: return parsed year, month, and day components.
  • Geometry: return a point with x and y coordinates.
  • Statistics: return named values such as minimum, maximum, and average.
  • Validation: return a status, error message, and optional normalized value.
  • Pagination: return items, nextPage, and totalCount in a result model.
  • Image processing: return red, green, and blue color channels.

In each case, a data class gives the related values meaningful names and keeps them together.

Take Quiz

Real Codebase Usage

In production Kotlin code, developers usually model related return values with a data class.

data class ParseResult(
    val value: Int?,
    val errorMessage: String?
)

fun parsePositiveInt(input: String): ParseResult {
    val number = input.toIntOrNull()
        ?: return ParseResult(null, "Enter a whole number")

    if (number <= 0) {
        return ParseResult(null, "Number must be positive")
    }

    return ParseResult(number, null)
}

This example uses early returns for invalid input and returns a structured result in every case.

Common choices in a codebase:

  • Use a data class for domain concepts and public APIs.
  • Use Pair for a small, obvious two-value result in local code.
  • Use Triple sparingly; unclear first, second, and third fields often indicate that a data class would be better.
  • Prefer existing domain types when available. For example, if you need an actual clock time rather than separate fields, java.time.LocalTime may be a better model on supported Kotlin platforms.
import java.time.LocalTime

fun getCurrentTime(): LocalTime = LocalTime.now()

LocalTime includes time-related behavior in addition to hour, minute, and second.

Common Mistakes

Expecting Kotlin to support Swift-style arbitrary tuples

This is not valid Kotlin syntax:

// Not valid Kotlin
fun getTime(): (Int, Int, Int) {
    return (14, 30, 45)
}

Use Triple<Int, Int, Int> or, preferably, a data class.

Using Triple when names matter

fun getTime(): Triple<Int, Int, Int> = Triple(14, 30, 45)

val time = getTime()
println(time.second) // This is the second item: 30, not the seconds value

Triple.second means the second position, not a time's seconds field. Avoid this ambiguity with TimeParts.

Returning a mutable collection for a fixed structure

fun getTime(): MutableList<Int> = mutableListOf(14, 30, 45)

A mutable list allows callers to change or reorder values. A data class better represents a fixed result with known fields.

Forgetting to validate time values

If values come from user input or external data, verify their ranges:

require(hour in 0..23) { "Hour must be between 0 and 23" }
require(minute in 0..59) { "Minute must be between 0 and 59" }
require(second in 0..59) { "Second must be between 0 and 59" }

Destructuring in the wrong order

val (minute, hour, second) = getTime()

Destructuring is positional. Variable names do not change which property is assigned. Keep the declaration in the data class constructor order.

Comparisons

OptionBest forAccess values asMain limitation
data classRelated values with clear meaningstime.hour or destructuringRequires defining a type
PairTwo small, temporary valuesfirst, second or destructuringOnly holds two values; names are generic
TripleThree quick, temporary valuesfirst, second, third or destructuringGeneric names can be unclear
List<Int> / IntArrayA variable-length sequence of same-kind valuesIndexes such as [0]Positions have no semantic names
LocalTimeA real time-of-day valuetime.hour, time.minuteDepends on the Java time API where applicable

For hour, minute, and second:

// Clear and maintainable
data class TimeParts(val hour: Int, val minute: Int, val second: Int)

// Valid, but less expressive
Triple<Int, Int, Int>
Take Quiz

Cheat Sheet

// Recommended: define named fields
data class TimeParts(val hour: Int, val minute: Int, val second: Int)

fun getTime(): TimeParts = TimeParts(14, 30, 45)

val time = getTime()
println(time.hour)

// Destructure a data class
val (hour, minute, second) = getTime()
// Built-in option for exactly three values
fun getTimeQuickly(): Triple<Int, Int, Int> = Triple(14, 30, 45)

val (hour, minute, second) = getTimeQuickly()
  • Kotlin returns one value; that value may be an object holding many fields.
  • Prefer a data class when fields have names and meaning.
  • Pair has first and second.
  • Triple has first, second, and third.
  • Destructuring assignment is positional.
  • Use an array or list for a variable number of values, not a fixed named record.

FAQ

Can a Kotlin function return multiple values?

Yes. It returns one object that can contain multiple values. Use a data class, Pair, Triple, a collection, or an existing type.

Does Kotlin have tuples like Swift?

Kotlin has Pair and Triple, but it does not have general tuple types such as (Int, Int, Int, Int).

Should I use Triple or a data class in Kotlin?

Use Triple for short-lived, obvious local code. Use a data class when each value has a meaningful name or the result is part of a reusable function API.

How do I unpack a returned data class in Kotlin?

Use destructuring:

val (hour, minute, second) = getTime()

Can I return more than three values from Kotlin?

Yes, define a data class with as many properties as needed. A data class is preferable to nesting Pair or Triple objects.

Is IntArray a good replacement for three return values?

Only when the values are truly an ordered sequence. For hour, minute, and second, named properties are safer and clearer.

What is the best type for an actual time of day?

When available in your environment, java.time.LocalTime is often best because it represents a time of day and provides related operations.

Take Quiz

Mini Project

Description

Create a small time parser that accepts a clock value in HH:MM:SS format and returns a named Kotlin object. This demonstrates returning multiple related values safely and validating external input before the rest of an application uses it.

Goal

Build a function that converts a valid time string into a TimeParts value and prints its separate components.

Requirements

Define a TimeParts data class with hour, minute, and second properties. Create a function that accepts a time string in HH:MM:SS format. Reject input that does not contain exactly three numeric components. Reject values outside the ranges 0–23 for hours and 0–59 for minutes and seconds. Use destructuring to print the parsed time components.

Take Quiz

Keep learning

Related questions

View more