1. 程式人生 > >Sealed classes in Kotlin: enums with super

Sealed classes in Kotlin: enums with super

Sealed classes in Kotlin are another new concept we didn’t have in Java, and open another new world of possibilities.

A sealed class allows you to represent constrained hierarchies in which an object can only be of one of the given types.

That is, we have a class with a specific number of subclasses. What we get in the end is a concept very similar to an enum. The difference is that in the enum we only have one object per type, while in the sealed classes we can have several objects of the same class.

This difference will allow objects from a sealed class to keep state. This will bring us some advantages that we’ll see in a moment, and also opens the doors to some functional ideas.

How to use sealed classes

Implementing a sealed class is actually very simple. Let’s use as an example a set of operations that can be applied to integers.

The implementation would be as follows:

123456 sealedclassOperation{classAdd(val value:Int):Operation()classSubstract(val value:Int):Operation()classMultiply(val value:Int):Operation()classDivide(val value:Int):Operation()}

We create a sealed class called Operation, which contains four types of operations: addition, subtraction, multiplication and division.

Want to learn Kotlin?

Check my free guide to create your first project in 15 minutes!

The good thing about this is that now when expressions will require us to provide branches for all possible types:

123456 fun execute(x:Int,op:Operation)=when(op){isOperation.Add->x+op.valueisOperation.Substract->x-op.valueisOperation.Multiply->x *op.valueisOperation.Divide->x/op.value}

If you leave any of the subclasses out,┬áwhen will complain and it won’t compile. If you implement them all, you don’t need else statement. And in general it won’t be recommended because that way we’re sure that we’re doing the right thing for all of them.

This is also great in case you decide to add a new operation, because it’ll fail at compile time and won’t run. Add a couple more operations: increment and decrement:

12345 sealedclassOperation{...objectIncrement:Operation()objectDecrement:Operation()}

You’ll see that the compiler now warns you that there is a problem. Just add branches for these new operations:

12345 fun execute(x:Int,op:Operation)=when(op){...Operation.Increment->x+1Operation.Decrement->x-1}

You may have noticed I did something different. I used objects instead of classes. This is because if a subclass doesn’t keep state, it can just be an object. All the instances you create for that class would be exactly the same, as they can’t have different state.

Then, in the when expression you can get rid of is for those cases. Here you can just compare the object, as there’s only one instance, you don’t need to check the type of object. It would work too if you keep is for those too.

If you think about it carefully, a sealed class where all subclasses are objects would be the same as an enum.

Moving side effects to a single point

Side effects are a very recurring concept in functional programming. Functional programming relies heavily on the idea that for a given function, same parameters will return the same result.

Any state that is modified may break this assumption. But any program needs to modify states, communicate with input/output elements, etc. So it’s important to spot these operations very specific places in our code that can be easily isolated.

For example, any operations performed on an Android view can be considered a side effect, as the status of the views is being modified and the functions aren’t aware of it.

We could create a sealed class that would allow us to do operations on our views. Based on the idea of our previous example:

12345678910111213 sealedclassUiOp{objectShow:UiOp()objectHide:UiOp()classTranslateX(val px:Float):UiOp()classTranslateY(val px:Float):UiOp()}fun execute(view:View,op:UiOp)=when(op){UiOp.Show->view.visibility=View.VISIBLEUiOp.Hide->view.visibility=View.GONEisUiOp.TranslateX->view.translationX=op.pxisUiOp.TranslateY->view.translationY=op.px}

Remember: operations that have no state can be objects, because we don’t need different instances.

Now you can create a Ui object that accumulates all interface operations that we want to do over a view, but it won’t execute them until the moment we want.

We’ll have a description of what we want to do, and then we can create a component that executes them:

123 classUi(val uiOps:List=emptyList()){operator fun plus(uiOp:UiOp)=Ui(uiOps+uiOp)}

The Ui class stores a list of operations, and specifies a sum operator that will help make everything a bit cleaner and easier to read. Now we can specify the list of operations that we want to perform:

1234567 val ui=Ui()+UiOp.Show+UiOp.TranslateX(20f)+UiOp.TranslateY(40f)+UiOp.Hiderun(view,ui)

And then run it. Here I’m just using a run function, but this could be a complete class if required.

123 fun run(view:View,ui:Ui){ui.uiOps.forEach{execute(view,it)}}

Imagine the power that gives you this. Right now all you do is run the operations sequentially, but this could be as complex as required.

This run function could be passed to another function or a class, and the way those operations are run would be totally interchangeable. Remember you can pass functions as arguments.

Conclusion

The concept of the sealed classes is very simple, but it’s the basis of a lot of new ideas you need to get used if you haven’t played with functional programming before.

I must say that I’m not yet able to take the most out of sealed classed due to my knowledge limitations in functional programming.

If you’re as passionate about this as I am, I encourage you to take a look at the the previous articles where you can learn more about Kotlin, or in the book where you’ll learn how to create a complete Android App using Kotlin from scratch.

I’m in love with Kotlin. I’ve been learning about it for a couple of years, applying it to Android and digesting all this knowledge so that you can learn it with no effort.

Shares

Like this:

Like Loading...

相關推薦

Sealed classes in Kotlin: enums with super

Sealed classes in Kotlin are another new concept we didn’t have in Java, and open another new world of possibilities. A sealed class allows you to re

Classes in Kotlin: More power with less effort (KAD 03)

Classes in Kotlin are as simple as possible so that you can express the maximum amount of logic with the less code possible. I’ll show quickly how yo

Data Classes in Kotlin: save a good bunch of lines of code (KAD 10)

We’ve already seen the classes in an earlier article, but data classes go a little further in helping us simplify our code. What are data classes? A

Variables in Kotlin, differences with Java. var vs val (KAD 02)

In this second chapter we will see how variables work in Kotlin, what is val and var , and when to use one or the other. I wanted to start from he

Using "when" expression in Kotlin: The "switch" with super powers

The switch expression in Java, and especially in Java 6, are extremely limited. Apart from a very short amount of types, it can not be used for anyth

Listeners with several functions in Kotlin. How to make them shine?

One question I get often is how to simplify the interaction with listeners that have several functions on Kotlin. For listeners (or any interfaces) w

Functional operations with collections in Kotlin (KAD 11)

I must admit that, for me, one of the most frustrating things when writing Java ccode is the list handling. Java 8 has some improvements in this resp

Say goodbye to NullPointerException. Working with nulls in Kotlin (KAD 19)

It had taken me too long to write an article to one of the most important parts of Kotlin: the treatment of nullity. Tony Hoare, the creator of the i

《A First Course in Abstract Algebra with Applications》-chaper1-數論-棣莫弗定理

mage strac str 技術分享 log -1 time img -c 定理1.24 (棣莫弗定理) 對每個實數x和每個正整數n有 基於棣莫弗定理的推論如下: 《A First Course in Abstract Algebr

[Python] Reuse Code in Multiple Projects with Python Modules

span return user __name__ argv pos sys class trac A module is a function extracted to a file. This allows you to import the function and

[Recompose] Create Stream Behaviors to Push Props in React Components with mapPropsStream

() ppr and create tin tee rom other fun Rather than using Components to push streams into other Components, mapPropsStream allows you to

[Tailwind] Create Custom Utility Classes in Tailwind

config fix paths AR XA asc check tom task In this lesson, we learn how to generate custom utility classes in tailwind. We add new propert

[React Native] Reduce Long Import Statements in React Native with Absolute Imports

other absolute fig Go react project only port gen In large React Native projects, it’s common to have long relative import paths li

[Typescript Kaop-ts] Use AOP in Vue Components with TypeScript and Kaop-ts

store json any username order term mov and all Aspect Oriented Programming, AOP, allows to reuse logic across an entire app in a very nea

[Node.js] Read a File in Node.js with fs.readFile and fs.readFileSync

sync spa enc erro buffer ron div examples nbsp We‘ll read a csv file in node.js both synchronously, and asynchronously. The file we‘re re

[Node.js] Write or Append to a File in Node.js with fs.writeFile and fs.writeFileSync

cti pen instead all write urn object The nod In node.js, you can require fs, and then call fs.writeFile with the filename, and data to wr

Error: Cannot fit requested classes in a single dex file (# methods: 149346 > 65536)

adl testin cati per 解決 tree and ons oid 引用第三方庫的jar文件,都有可能會觸發這個錯誤。解決方案如下: 參考《[Android]Cannot fit requested classes in a single dex file.

Darknet: Open Source Neural Networks in C - Classifying With darknet19.weights Models

Darknet: Open Source Neural Networks in C - Classifying With darknet19.weights Models Darknet is an open source neural network framework written

ValueError: This solver needs samples of at least 2 classes in the data, but the data contains only

sklearn報錯: ValueError: This solver needs samples of at least 2 classes in the data, but the data contains only one class: 0.0 博主是在使用sklearn.learning

《Detecting Text in Natural Image with Connectionist Text Proposal Network》論文閱讀之CTPN

前言 2016年出了一篇很有名的文字檢測的論文:《Detecting Text in Natural Image with Connectionist Text Proposal Network》,這個深度神經網路叫做CTPN,直到今天這個網路框架一直是OCR系統中做文字檢測的一個常用網路,極大