Kotlin Data Sealed Classes
# Kotlin Data Classes and Sealed Classes
* * *
## Data Classes
Kotlin can create a class that only holds data, using the keyword `data`:
```kotlin
data class User(val name: String, val age: Int)
The compiler automatically derives the following member functions from all declared properties in the primary constructor:
* `equals()` / `hashCode()`
* `toString()` format like `"User(name=John, age=42)"`
* `componentN() functions` corresponding to the properties, in the order of declaration
* `copy()` function
If any of these functions are explicitly defined in the class body or inherited from a superclass, they will not be generated.
To ensure consistent and meaningful generated code, data classes need to meet the following requirements:
* The primary constructor must have at least one parameter.
* All primary constructor parameters must be marked as `val` or `var`;
* Data classes cannot be declared as `abstract`, `open`, `sealed`, or `inner`;
* Data classes cannot inherit from other classes (but they can implement interfaces).
### Copying
Copying is done using the `copy()` function. We can use this function to copy an object and modify some of its properties. For the `User` class above, its implementation would look something like this:
```kotlin
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)
### Example
Using the `copy` function to copy the `User` data class and modify the `age` property:
```kotlin
data class User(val name: String, val age: Int)
fun main(args: Array) {
val jack = User(name = "Jack", age = 1)
val olderJack = jack.copy(age = 2)
println(jack)
println(olderJack)
}
The output will be:
User(name=Jack, age=1)
User(name=Jack, age=2)
### Data Classes and Destructuring Declarations
Component functions allow data classes to be used in destructuring declarations:
```kotlin
val jane = User("Jane", 35)
val (name, age) = jane
println("$name, $age years of age") // prints "Jane, 35 years of age"
### Standard Data Classes
The standard library provides `Pair` and `Triple`. In most cases, named data classes are a better design choice because they make the code more readable and provide meaningful names and properties.
* * *
## Sealed Classes
Sealed classes are used to represent restricted class hierarchies: when a value can have one of a limited number of types, but no other type. In a sense, they are an extension of enum classes: the set of values for an enum type is also restricted, but each enum constant exists only as a single instance, whereas a subclass of a sealed class can have multiple instances that can contain state.
To declare a sealed class, use the `sealed` modifier on the class. A sealed class can have subclasses, but all of them must be nested within the sealed class.
`sealed` cannot be applied to interfaces, abstract classes (it will produce a warning, but no compilation error).
```kotlin
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
fun eval(expr: Expr): Double = when (expr) {
is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
NotANumber -> Double.NaN
}
The key benefit of using sealed classes is when using `when` expressions. If you can verify that the statement covers all cases, you don't need to add an `else` clause to the statement.
```kotlin
fun eval(expr: Expr): Double = when(expr) {
is Expr.Const -> expr.number
is Expr.Sum -> eval(expr.e1) + eval(expr.e2)
Expr.NotANumber -> Double.NaN
// No `else` clause is needed because we have covered all cases
}
YouTip