Kotlin, Zero to Kotlin Hero

Zero to Kotlin Hero: Data classes and Sealed classes

The previous article was about Functions in Kotlin. In this article, get ready to understand data and sealed classes.

Data Classes

As the name implies, data classes pretty much hold data.

A lot of times when building software, we may create classes that just store data and do nothing else. If we had to create a User class in Java, we would have to write boilerplate code. See below:

public class User{
    private String firstname;
    private String lastname;
    private String username;
    private String email;

    public User(String firstname, String lastname, String username, String email) {
        this.firstname = firstname;
        this.lastname = lastname;
        this.username = username;
        this.email = email;
    }
    
    public String getFirstname() {
        return firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    public String getLastname() {
        return lastname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    public String getUsername() { 
        return username; 
    } 

    public void setUsername(String username) { 
        this.username = username; 
    }

    public String getEmail() { 
       return email; 
    } 

    public void setEmail(String email) { 
       this.email = email; 
    }
    
    @Override
    public boolean equals(Object o) {
        //code to override equals method 
    }

    @Override
    public int hashCode() {
        //code to override hashcode method 
    }

    @Override
    public String toString() {
       //code to override hashcode method 
    }
}

I truly apologise for making you scroll through this boilerplate code. Imagine if we had a User with 10 or more properties, the Java code would have even been longer. Kotlin’s data classes make doing stuff like this a lot easier. Take a look:

data class User(val name: firstname, val name: lastname, val name: username, val name: email)

Just one line. Yes. I didn’t forget to add anything.

The equals(), hashCode(), toString(), copy() and componentN() functions are added automatically.

 

What is the copy() function?

Data classes are immutable. The copy() function is created so that we can copy an object and alter some of its data. For example, if we want to change the first name of a certain user, this can be done by writing:

val olduser = User("Nenne", "Nwodo", "adoranwodo", "nennenwodo@gmail.com")
val newuser = olduser.copy(firstname = "Adora")

 

Cool… So how do we use Data Classes?

It’s pretty simple. But before we see how to use them, it’s important to know the requirements.

  • The primary constructor needs to have at least one parameter e.g. data class User(val name: firstname)
  • All primary constructor parameters need to be marked as val or var;
  • Data classes cannot be abstract, open, sealed or inner;

 

Now, we can create and instantiate our data class. As seen above, they are created like other classes but have the data keyword present.

We can instantiate our User data class and access it’s properties like so:

val user = User("Nenne", "Nwodo", "adoranwodo", "nennenwodo@gmail.com")
val firstname = user.firstname 
val lastname = user.lastname 
val username = user.username 
val email = user.email

print("$firstname $lastname is user $username and their email is $email")

 

One more thing. We can also destructure declarations. This means we can treat properties of objects as individual values. So instead of doing what we just did (above), there is a shorter way:

val user = User("Nenne", "Nwodo", "adoranwodo", "nennenwodo@gmail.com")
val (firstname, lastname, username,email) = user

print("$firstname $lastname is user $username and their email is $email")

 

Sealed Classes

Sealed classes are used for representing restricted class hierarchies.

Enums are used when a value can have one of the types from a limited set, but cannot have any other type. e.g. imagine if we had days of the week. They can either be Monday, Tuesday, Wednesday… or Sunday 👍🏼 but they can never be January 👎🏼.

Sealed classes can be inherited from. 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 which can contain state.

Sealed classes are to be used when the options are functionally different. If the options differ only in meaning, I would advise you used the basic enums.

To show that sealed classes are pretty much enums that schooled abroad, an example is illustrated below:

sealed class Expr {
    data class And(val a: Int, val b: Int) : Expr()
    data class Or(val a: Int, val b: Int) : Expr()
    data class Xor(val a: Int, val b: Int) : Expr()
}

fun eval(expr: Expr): Int = when(expr) {
        is expr.And -> { expr.a and expr.b }    //and operation
        is expr.Or -> {expr.a or expr.b }       //or operation
        is expr.Xor -> {expr.a xor expr.b }    //xor operation
}

It can now be guaranteed that any time you have an instance of Expr, It is either an Or, And or Xor.

 

Conclusion

We have seen data classes and sealed classes in Kotlin. Get ready to know about Kotlin Extensions in the next article!

 

Spread the love

2 thoughts on “Zero to Kotlin Hero: Data classes and Sealed classes

  1. My brother recommended I might like this website. He was entirely right. This post truly made my day. You can not imagine simply how much time I had spent for this information! Thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *