📖 Scenario: Imagine you are building a simple app that handles different types of notifications: Email, SMS, and Push notifications. Each notification type has its own way of showing a message.
🎯 Goal: You will create a sealed class hierarchy to represent these notification types. Then, you will write code to handle each notification type safely and print the correct message.
📋 What You'll Learn
Create a sealed class called Notification.
Create three subclasses: Email, SMS, and Push inside Notification.
Add a message property to each subclass.
Write a function showNotification that takes a Notification and prints a message based on its type using when.
Call showNotification for each notification type.
💡 Why This Matters
🌍 Real World
Sealed classes help you model fixed sets of types, like different notification kinds, so your app can handle them safely and clearly.
💼 Career
Understanding sealed classes is important for Kotlin developers to write safe and maintainable code, especially when working with restricted hierarchies or state machines.
Progress0 / 4 steps
1
Create the sealed class and subclasses
Create a sealed class called Notification. Inside it, create three subclasses: Email, SMS, and Push. Each subclass should have a message property of type String.
Kotlin
Hint
Use sealed class Notification and inside it define data class Email, SMS, and Push each with a message property.
2
Create a function to show notifications
Create a function called showNotification that takes a parameter notification of type Notification. Inside the function, use a when expression to check the type of notification and print the message with a prefix: "Email: ", "SMS: ", or "Push: ".
Kotlin
Hint
Use when (notification) and check for each subclass with is Notification.Email, etc. Print the message with the correct prefix.
3
Create instances of each notification type
Create three variables: emailNotification, smsNotification, and pushNotification. Assign each one an instance of Notification.Email, Notification.SMS, and Notification.Push respectively, with messages: "Welcome to your inbox!", "You have a new text.", and "You have a new alert."
Kotlin
Hint
Create variables with exact names and assign instances of each subclass with the given messages.
4
Print messages for all notifications
Call showNotification for each variable: emailNotification, smsNotification, and pushNotification. This will print the messages with their prefixes.
Kotlin
Hint
Call showNotification with each notification variable to print their messages.
Practice
(1/5)
1. What is the main purpose of using sealed classes in Kotlin?
easy
A. To create classes that cannot be instantiated
B. To allow any class in any file to inherit from it
C. To restrict which classes can inherit from it, all in the same file
D. To automatically generate data classes
Solution
Step 1: Understand sealed class inheritance rules
Sealed classes restrict subclassing to the same file, limiting which classes can extend them.
Step 2: Compare options with sealed class purpose
Only To restrict which classes can inherit from it, all in the same file correctly describes this restriction; others describe unrelated features.
Final Answer:
To restrict which classes can inherit from it, all in the same file -> Option C
Quick Check:
Sealed classes restrict inheritance = A [OK]
Hint: Sealed classes limit subclasses to one file only [OK]
Common Mistakes:
Thinking sealed classes prevent instantiation
Confusing sealed classes with abstract classes
Believing sealed classes allow open inheritance
2. Which of the following is the correct syntax to declare a sealed class named Shape in Kotlin?
easy
A. abstract sealed class Shape
B. open sealed class Shape {}
C. sealed interface Shape {}
D. sealed class Shape {}
Solution
Step 1: Recall sealed class declaration syntax
Sealed classes are declared with the keyword sealed class followed by the name and body.
Step 2: Check each option's correctness
sealed class Shape {} matches the correct syntax. open sealed class Shape {} wrongly combines open and sealed. sealed interface Shape {} uses sealed interface which is invalid. abstract sealed class Shape {} wrongly combines abstract and sealed.
Final Answer:
sealed class Shape {} -> Option D
Quick Check:
Correct sealed class syntax = D [OK]
Hint: Use only 'sealed class ClassName {}' to declare sealed classes [OK]
Common Mistakes:
Adding 'open' or 'abstract' keywords with sealed
Using 'sealed interface' instead of 'sealed class'
Forgetting curly braces after class name
3. Consider the following Kotlin code using sealed classes:
sealed class Result {
data class Success(val data: String) : Result()
object Failure : Result()
}
fun handle(result: Result) = when(result) {
is Result.Success -> "Data: ${result.data}"
is Result.Failure -> "Failed"
}
println(handle(Result.Success("OK")))
What is the output when this code runs?
medium
A. "Data: OK"
B. "Failed"
C. Compilation error due to missing else branch
D. Runtime exception
Solution
Step 1: Understand sealed class and when expression
The sealed class Result has two subclasses: Success and Failure. The when expression covers both cases without else.
Step 2: Trace the function call with Success("OK")
The argument is Result.Success("OK"), so the first branch matches, returning "Data: OK".
Final Answer:
"Data: OK" -> Option A
Quick Check:
Sealed class when covers all cases = "Data: OK" [OK]
Hint: Sealed classes allow exhaustive when without else [OK]
Common Mistakes:
Thinking else branch is required for sealed classes
Confusing Success and Failure outputs
Expecting runtime errors from sealed classes
4. The following Kotlin code tries to compile but fails. What is the error?
sealed class Animal
class Dog : Animal()
class Cat : Animal()
Why does this code cause a compilation error?
medium
A. Sealed classes cannot have subclasses
B. Subclasses Dog and Cat must be declared in the same file as Animal
C. Dog and Cat must be declared as sealed classes too
D. Animal must be declared as an abstract class instead
Solution
Step 1: Recall sealed class subclass rules
Sealed classes restrict subclasses to be declared in the same file.
Step 2: Identify the error cause
Dog and Cat are subclasses but declared outside the sealed class file, causing compilation error.
Final Answer:
Subclasses Dog and Cat must be declared in the same file as Animal -> Option B
Quick Check:
Sealed subclasses must be in same file = B [OK]
Hint: All sealed subclasses must be in the same file [OK]
Common Mistakes:
Thinking sealed classes forbid any subclassing
Believing subclasses must be sealed too
Confusing sealed with abstract class rules
5. You want to model a fixed set of user roles in Kotlin using sealed classes: Admin, Guest, and Member. Which approach correctly uses sealed classes to restrict roles and safely handle all cases?
hard
A. sealed class UserRole {
object Admin : UserRole()
object Guest : UserRole()
object Member : UserRole()
}
fun describe(role: UserRole) = when(role) {
is UserRole.Admin -> "Admin user"
is UserRole.Guest -> "Guest user"
is UserRole.Member -> "Member user"
}
B. open class UserRole
class Admin : UserRole()
class Guest : UserRole()
class Member : UserRole()
fun describe(role: UserRole) = when(role) {
is Admin -> "Admin user"
is Guest -> "Guest user"
is Member -> "Member user"
else -> "Unknown"
}
D. abstract class UserRole
object Admin : UserRole()
object Guest : UserRole()
object Member : UserRole()
fun describe(role: UserRole) = when(role) {
is Admin -> "Admin user"
is Guest -> "Guest user"
is Member -> "Member user"
}
Solution
Step 1: Use sealed class to restrict subclasses
sealed class UserRole {
object Admin : UserRole()
object Guest : UserRole()
object Member : UserRole()
}
fun describe(role: UserRole) = when(role) {
is UserRole.Admin -> "Admin user"
is UserRole.Guest -> "Guest user"
is UserRole.Member -> "Member user"
} declares a sealed class with all subclasses as objects inside the same file, restricting roles properly.
Step 2: Check safe handling with exhaustive when
The when expression covers all subclasses without else, ensuring safe handling.
Final Answer:
sealed class UserRole {
object Admin : UserRole()
object Guest : UserRole()
object Member : UserRole()
}
fun describe(role: UserRole) = when(role) {
is UserRole.Admin -> "Admin user"
is UserRole.Guest -> "Guest user"
is UserRole.Member -> "Member user"
} -> Option A
Quick Check:
Sealed class + exhaustive when = safe fixed roles [OK]
Hint: Use sealed class with all subclasses inside one file [OK]
Common Mistakes:
Using open or abstract classes without sealing
Missing exhaustive when branches
Using sealed interface incorrectly
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.