You are currently viewing Kotlin Sealed Class

Kotlin Sealed Class

What are sealed classes?

A Sealed class is a class that restricts the inheritance hierarchy by allowing a fixed set of subclasses. All the subclasses must be declared within the same file as the sealed class itself. These subclasses can be of any type a data class, an object, a regular class, or another sealed class. Sealed classes are useful when you want to represent a limited set of related classes or types and ensure that all possible subclasses are known at compile time. Third-party clients can’t extend sealed class.

The sealed class in Kotlin has several key features that make :

  1. Type Safety at Compile-Time: Sealed classes ensure type safety by restricting the types to be matched at compile-time, preventing the introduction of new subclasses at runtime.
  2. Subclass Definition Scope: Subclasses of a sealed class must be defined within the same Kotlin file or any scope where the sealed class is visible. They are not required to be defined directly within the sealed class.
  3. Restriction on Inheritance: Sealed classes cannot be inherited or extended by other classes. They restrict the inheritance hierarchy to a predefined set of subclasses.
  4. Limited Set of Subclasses: Sealed classes allow for a limited set of subclasses, enhancing code predictability and maintainability.
  5. Representation of States: Sealed classes are often used to represent a set of possible states or outcomes in a program.
  6. Constructor, Properties, and Methods: Sealed classes can have constructors, properties, and methods similar to regular classes.
  7. Protected Constructor: The constructor of a sealed class is implicitly protected by default. It can also be explicitly marked as private, but public and internal visibility is not allowed.
  8. Instantiation Restriction: Sealed classes cannot be instantiated directly; they must be instantiated through one of their subclasses.

How to declare and use sealed classes?

To declare a sealed class in Kotlin, you use the sealed keyword followed by the name of the class. The sealed class can have one or more subclasses, and all of these subclasses are defined within the same file where the sealed class is declared. Here’s the basic syntax:

sealed class MySealedClass {
    // Subclasses go here
}

You then define the subclasses inside the sealed class using the data class or object keyword, depending on whether you need instances with data or singleton objects. Here’s an example:

sealed class Result {
    data class Success(val data: String) : Result()
    data class Error(val message: String) : Result()
    object Loading : Result()
}

In this example, Result is a sealed class with three subclasses: Success, Error, and Loading. Success and Error are data classes, each carrying specific data, while Loading is an object representing a loading state.

Example of a Sealed Class

Let’s consider an example where a sealed class is used to model different states of an order in an e-commerce system:

sealed class OrderState {
    object Pending : OrderState()
    data class Shipped(val trackingNumber: String) : OrderState()
    data class Delivered(val deliveryDate: String) : OrderState()
    object Canceled : OrderState()
}

The OrderState sealed class has four subclasses: Pending, Shipped, Delivered, and Canceled, representing different states an order can be in. Shipped and Delivered have additional data associated with them (trackingNumber and deliveryDate).

fun processOrder(orderState: OrderState) {
    when (orderState) {
        is OrderState.Pending -> println("Order is pending processing.")
        is OrderState.Shipped -> println("Order has been shipped. Tracking number: ${orderState.trackingNumber}")
        is OrderState.Delivered -> println("Order has been delivered on ${orderState.deliveryDate}.")
        is OrderState.Canceled -> println("Order has been canceled.")
    }
}

fun main() {
    val pendingOrder = OrderState.Pending
    val shippedOrder = OrderState.Shipped(trackingNumber = "123456789")
    val deliveredOrder = OrderState.Delivered(deliveryDate = "2022-03-01")
    val canceledOrder = OrderState.Canceled

    processOrder(pendingOrder)
    processOrder(shippedOrder)
    processOrder(deliveredOrder)
    processOrder(canceledOrder)
}

Explanation:

The processOrder function handles the processing of orders based on their state. It takes a OrderState parameter. The when expression in the processOrder function is used to perform different actions based on the type of the orderState parameter((Pending, Shipped, or Delivered, Canceled). It checks the type of orderState using is checks for each possible subclass of the OrderState sealed class and executes the corresponding block of code based on the type.

Main Function (main): In the main function, instances of different order states are created, and their processing is demonstrated using the processOrder function.

What are the Similarities and difference between sealed and enum classes?

Similarities

  • Both sealed classes and enum classes provide a way to define a limited set of possible values or states.
  • They are useful when you want to ensure that a variable can only take on a specific set of values.

Differences

FeatureSealed ClassEnum Class
Number of InstancesMultiple instances for each subclass.Single instance for each enum constant.
Data and BehaviorEach subclass can have properties and methods.Enum constants can have properties and methods.
InstantiationSubclasses can be instantiated with different data.Enum constants are typically singletons.
Nested ClassesAllows the declaration of nested classes within the sealed class.Does not allow nested classes within the enum class.
Use CaseUsed for representing a restricted set of related states or outcomes.Used for representing a fixed set of distinct values or constants.
FlexibilityMore flexible in terms of data and behavior within each subclass.Less flexible, but provides a fixed set of named values.
Pattern MatchingOften used with when expressions for exhaustive pattern matching.Also used with when expressions, but the set of values is known at compile time.
Exampleskotlin sealed class Result { ... }kotlin enum class Color { RED, GREEN, BLUE }
Difference between sealed and enum classes

Advantages of Sealed Classes in Android Kotlin:

  1. Code Clarity: Sealed classes make the code more readable and self-explanatory by explicitly defining a restricted set of possibilities.
  2. Exhaustive Handling: The use of sealed classes with when expressions ensures that all possible cases are handled, providing better compile-time safety.
  3. Maintenance: Sealed classes can simplify maintenance by encapsulating related classes within a single hierarchy, making it easier to manage changes and additions to the code.
  4. Pattern Matching: Sealed classes facilitate pattern matching, making it easier to express logic based on the type of an object in a concise and readable way.

Leave a Reply