How to Use Sealed Classes In Kotlin?

11 minutes read

Sealed classes in Kotlin are used to represent restricted class hierarchies. They are typically used when you have a class hierarchy in which all possible subclasses are known at compile-time and you want to restrict it to a specific set.


To define a sealed class, you use the sealed modifier before the class keyword. For example:

1
sealed class Fruit


Sealed classes can have subclasses defined within the same file where the sealed class is declared, making it easier to manage the hierarchy.


Sealed classes are useful in conjunction with the when expression (similar to the switch statement in other programming languages). When using a when expression, it is necessary to provide a branch for each possible subclass of a sealed class. This helps ensure that all cases are covered and the code is exhaustive. Here's an example:

1
2
3
4
5
6
7
fun identifyFruit(fruit: Fruit) {
    when (fruit) {
        is Apple -> println("It's an apple")
        is Orange -> println("It's an orange")
        is Banana -> println("It's a banana")
    }
}


In this example, Apple, Orange, and Banana are subclasses of the sealed class Fruit. Since we are using a when expression, we must provide a branch for each possible subclass.


Sealed classes can also have properties, methods, and constructors like regular classes. However, they cannot be directly instantiated using the new keyword since they are abstract. Instead, instances of sealed classes can only be created through one of their subclasses.


In summary, sealed classes in Kotlin provide a way to restrict class hierarchies to a specific set of subclasses. They allow for exhaustive checking using the when expression and can help in creating more structured and type-safe code.

Best Kotlin Books to Read in 2024

1
Atomic Kotlin

Rating is 5 out of 5

Atomic Kotlin

2
Kotlin in Action

Rating is 4.9 out of 5

Kotlin in Action

3
Kotlin Cookbook: A Problem-Focused Approach

Rating is 4.8 out of 5

Kotlin Cookbook: A Problem-Focused Approach

4
Head First Kotlin: A Brain-Friendly Guide

Rating is 4.7 out of 5

Head First Kotlin: A Brain-Friendly Guide

5
Kotlin Programming: The Big Nerd Ranch Guide (Big Nerd Ranch Guides)

Rating is 4.6 out of 5

Kotlin Programming: The Big Nerd Ranch Guide (Big Nerd Ranch Guides)

6
Effective Kotlin: Best Practices (Kotlin for Developers Book 5)

Rating is 4.5 out of 5

Effective Kotlin: Best Practices (Kotlin for Developers Book 5)

7
Java to Kotlin: A Refactoring Guidebook

Rating is 4.4 out of 5

Java to Kotlin: A Refactoring Guidebook

8
Learn to Program with Kotlin: From the Basics to Projects with Text and Image Processing

Rating is 4.3 out of 5

Learn to Program with Kotlin: From the Basics to Projects with Text and Image Processing


How to use sealed classes for implementing a simple calculator?

To use sealed classes for implementing a simple calculator, you can follow these steps:


Step 1: Define the sealed class called Operation to represent different arithmetic operations. This class will have a limited number of possible subclasses, each representing a specific operation (e.g., addition, subtraction, multiplication, division). This ensures that all possible operations are accounted for and allows for easy extensibility.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
sealed class Operation {
    abstract fun performOperation(a: Int, b: Int): Int

    object Addition : Operation() {
        override fun performOperation(a: Int, b: Int): Int {
            return a + b
        }
    }

    object Subtraction : Operation() {
        override fun performOperation(a: Int, b: Int): Int {
            return a - b
        }
    }

    object Multiplication : Operation() {
        override fun performOperation(a: Int, b: Int): Int {
            return a * b
        }
    }

    object Division : Operation() {
        override fun performOperation(a: Int, b: Int): Int {
            return a / b
        }
    }
}


Step 2: Use the Operation subclass objects to perform calculations. You can create a Calculator class that takes two operands and an operation as parameters and returns the result.

1
2
3
4
5
class Calculator {
    fun calculate(a: Int, b: Int, operation: Operation): Int {
        return operation.performOperation(a, b)
    }
}


Step 3: Use the Calculator class to perform calculations by providing the operands and the desired operation.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
fun main() {
    val calculator = Calculator()

    val result = calculator.calculate(5, 3, Operation.Addition)
    println("Addition Result: $result")

    val result = calculator.calculate(5, 3, Operation.Subtraction)
    println("Subtraction Result: $result")

    val result = calculator.calculate(5, 3, Operation.Multiplication)
    println("Multiplication Result: $result")

    val result = calculator.calculate(6, 3, Operation.Division)
    println("Division Result: $result")
}


This implementation allows you to easily add more operations to the sealed class hierarchy without modifying other parts of the code. It also ensures that all possible operations are handled correctly, reducing the chances of runtime errors.


How to provide extension functions for sealed classes in Kotlin?

To provide extension functions for sealed classes in Kotlin, you can use Kotlin's powerful features like when expressions and smart casts. Follow these steps:

  1. Define a sealed class with its subclasses:
1
2
3
4
sealed class Result {
    data class Success(val value: Int) : Result()
    data class Error(val message: String) : Result()
}


  1. Write an extension function for the sealed class outside its scope (e.g., in a separate file or a different class):
1
2
3
4
5
6
fun Result.printValue() {
    when (this) {
        is Result.Success -> println("Success: $value")
        is Result.Error -> println("Error: $message")
    }
}


  1. Now, you can use the extension function on instances of the sealed class:
1
2
3
4
5
val successResult = Result.Success(42)
successResult.printValue() // Output: Success: 42

val errorResult = Result.Error("Something went wrong")
errorResult.printValue() // Output: Error: Something went wrong


With extension functions, you can easily define additional behaviors or operations for sealed classes without modifying their original implementations.


What is the relationship between sealed classes and polymorphism in Kotlin?

In Kotlin, sealed classes and polymorphism are closely related concepts that often work together to enable safe and exhaustive handling of a limited set of possible types.


A sealed class is a class that restricts its subclasses to a specific, limited set defined within the sealed class itself. This means that all the subclasses of a sealed class are implicitly defined within the same file as the sealed class itself. Sealed classes are declared using the sealed modifier.


Polymorphism, on the other hand, is a fundamental principle of object-oriented programming that allows objects of different classes to be treated as objects of a common superclass or interface. Polymorphism enables you to write code that is generic and reusable, operating on objects of different specific types in a uniform way.


The relationship between sealed classes and polymorphism lies in the way sealed classes enable pattern matching and exhaustive handling of all possible subclasses using a when statement. Since the subclasses of a sealed class are limited and known at compile-time, the Kotlin compiler can enforce exhaustive when statements, meaning that the compiler will require you to handle all possible subclasses explicitly. This enhances safety and helps catch potential errors during compilation.


By leveraging polymorphism with sealed classes, you can use a sealed class in the when statement, and Kotlin will ensure that all possible subclasses are handled. This way, whenever you add a new subclass, the compiler will notify you about any missing handling code, prompting you to update your code accordingly.


Overall, sealed classes and polymorphism are closely tied together to provide a powerful mechanism for working with a restricted set of types safely and exhaustively in Kotlin.


What is the role of sealed classes in pattern matching?

Sealed classes play a crucial role in pattern matching by providing a limited set of known subtypes that can be matched against in a exhaustive and safe manner.


Pattern matching is a language feature that allows developers to perform conditional branching based on the structure of objects. It is commonly used in functional programming languages and is becoming increasingly popular in modern programming languages like Kotlin and C#.


Sealed classes, also known as discriminated unions or algebraic data types in other languages, are designed to represent a restricted hierarchy of types. In these classes, all possible subtypes are declared within the sealed class itself, and any additional subclasses outside the sealed class are not allowed. This ensures that all possible subtypes are known upfront.


When using pattern matching, developers can use the sealed class as an exhaustive pattern match. This means that in order to handle all possible subtypes, every case of the sealed class needs to be handled separately. The compiler will raise an error if a case is missed, which helps prevent logical errors and improve code reliability.


Sealed classes help developers write more concise, readable, and maintainable code. They provide a higher level of safety by enforcing exhaustive matching, ensuring that all possible cases are handled explicitly. This reduces the risk of runtime errors and improves code correctness. Additionally, sealed classes make it easier to reason about code and understand all the possible states an object can be in.


Overall, sealed classes enhance pattern matching by encapsulating a restricted set of types in a hierarchy and enabling exhaustive matching, resulting in cleaner code and improved code reliability.

Twitter LinkedIn Telegram Whatsapp

Related Posts:

To create a Kotlin UInt from Java, you can use the following code snippets:In Java: import kotlin.jvm.JvmField; public class JavaClass { @JvmField public static int createUInt() { return 10; } } In Kotlin: val uintValue = JavaClass.createU...
Data classes in Kotlin are a convenient way to create classes that hold data. They automatically provide several useful functions like equals(), hashCode(), toString(), and copy(). These functions are generated behind the scenes by the Kotlin compiler based on...
Working with the Kotlin Collections API allows you to efficiently manage and manipulate collections of data in your Kotlin code. Kotlin provides a rich set of built-in functions and operators that make it easy to perform common operations on lists, sets, and m...