Sealed Classes With When Statements Kotlin

Introduction


Kotlin is a new generation language officially for Android developement. Well  --- we are taking about the sealed classes. According to official docs "Sealed classes are used for representing restricted class hierarchies wherein the object or the value can have value only among one of the types, thus fixing your type hierarchies. Sealed classes are commonly used in cases, where you know what a given value to be only among a given set of options".

As the name implies, the sealed classes are restricted classes or bound class heirarchies. Sealed classes ensure type-safety by restricting the types to be matched at compile-time rather than at runtime.

How to define a Sealed Class?

  • By default a sealed class is abstract, therefore it cannot be instantiated.
  • Constructor by default is private. 
  • To define a sealed class, just precede the class modifier with the sealed keyword.
A typical structure of sealed class is as follows: 
  1. sealed class Demo  
  2. fun main(args: Array)  
  3. {  
  4.     var d = Demo()     //compiler error Demo can not instantiated
  5. }  
Let's have a look at the complete structure with some methods in it.
  1. sealed class Demo {   
  2.     class A : Demo() {   
  3.         fun display()   
  4.         {   
  5.             println("Subclass A of sealed class Demo")   
  6.         }   
  7.     }   
  8.     class B : Demo() {   
  9.         fun display()   
  10.         {   
  11.             println("Subclass B of sealed class Demo")   
  12.         }   
  13.     }   
  14. }   
  15. fun main()   
  16. {   
  17.     val obj = Demo.B()   
  18.     obj.display()   
  19.   
  20.     val obj1 = Demo.A()   
  21.     obj1.display()   
  22. }   
Output

Subclass B of sealed class Demo
Subclass A of sealed class Demo
 

Difference between Enums and Sealed classes

 
Sealed classes in Kotlin can be thought of  as enums on steroids. Sealed classes allow us to create instances with different types, unlike Enums which restrict us to use the same type for all enum constants.

The following is not possible in enum classes.
  1. enum class Months(string: String){  
  2. January("Jan"), February(2),  
  3. }  
The enums can take single types of constants. This situation is overcome by Sealed classes which holds the different type of constants.
  1. sealed class Months {  
  2.     class January(var shortHand: String) : Months()  
  3.     class February(var number: Int) : Months()  
  4.     class March(var shortHand: String, var number: Int) : Months()  
  5. }  

Sealed classes with when

 
Sealed classes are widely used with the when statements as the choices become the subclasses and their type acts as a case.
Let's see how when is used with sealed classes. We have a sealed class with named as shape with three different subclasses. Now this subclass became the choice in when.
 
Example 1
  1. sealed class Shape{  
  2.     class Circle(var radius: Float): Shape()  
  3.     class Square(var length: Int): Shape()  
  4.     class Rectangle(var length: Int, var breadth: Int): Shape()  
  5. }  
Now convert the above code with "when".
  1. fun eval(e: Shape) =  
  2.         when (e) {  
  3.             is Shape.Circle -> println("Circle area is ${3.14*e.radius*e.radius}")  
  4.             is Shape.Square -> println("Square area is ${e.length*e.length}")  
  5.             is Shape.Rectangle -> println("Rectagle area is ${e.length*e.breadth}")  
  6.         }  
Let's call the above method in the main function.
  1. fun main(args: Array<String>) {  
  2.   
  3.     var circle = Shape.Circle(4.5f)  
  4.     var square = Shape.Square(4)  
  5.     var rectangle = Shape.Rectangle(4,5)  
  6.   
  7.     eval(circle)  
  8.     eval(square)  
  9.     eval(rectangle)  
  10.     //eval(x) //compile-time error.  
  11.   
  12. }  
Output
 
Circle area is 63.585
Square area is 16
Rectangle area is 20
 
Example 2
 
Let's see another example to demonstrate when statment with sealed class.
  1. // A sealed class with a string property   
  2. sealed class Fruit   
  3.     (val x: String)   
  4. {   
  5.     // Two subclasses of sealed class defined within   
  6.     class Apple : Fruit("Apple")   
  7.     class Mango : Fruit("Mango")   
  8. }   
  9.   
  10. // A subclass defined outside the sealed class   
  11. class Pomegranate: Fruit("Pomegranate")   
  12.   
  13. // A function to take in an object of type Fruit   
  14. // And to display an appropriate message depending on the type of Fruit   
  15. fun display(fruit: Fruit){   
  16.     when(fruit)   
  17.     {   
  18.         is Fruit.Apple -> println("${fruit.x} is good for iron")   
  19.         is Fruit.Mango -> println("${fruit.x} is delicious")   
  20.         is Pomegranate -> println("${fruit.x} is good for vitamin d")   
  21.     }   
  22. }   
  23. fun main()   
  24. {   
  25.     // Objects of different subclasses created   
  26.     val obj = Fruit.Apple()   
  27.     val obj1 = Fruit.Mango()   
  28.     val obj2 = Pomegranate()   
  29.   
  30.     // Function called with different objects   
  31.     display(obj)   
  32.     display(obj1)   
  33.     display(obj2)   
  34. }   
Output
 
Apple is good for iron.
Mango is delicious.
Pomegranate is good for vitamin d.