Using Kotlin’s sealed class to approximate Swift’s enum with associated data

David Pacheco
2 min readMay 26, 2017

--

Swift has a great feature for an enum type that allows you to associated data
with it. Here is the example given on the Swift Programming Language site:

enum Barcode {
case UPCA(Int, Int, Int, Int)
case QRCode(String)
}

This should be read as:

Define an enumeration type called Barcode, which can take either a value of UPCA with an associated value of type (Int, Int, Int, Int), or a value of QRCode with an associated value of type String.

Here is an example of creating an instance of the UPCA type:

var productBarcode = Barcode.UPCA(8, 85909, 51226, 3)

Trying to emulate this in Kotlin

Via interfaces

In looking for a way to implement this in Kotlin we initially used an interface as a type indicator and then created classes for each type value that defined it’s required properties. Here is the Barcode example using an interface in Kotlin:

interface Barcode
class UPCA(val numberSystem: Int, val manufacturer: Int, val product: Int, val check: Int) : Barcode
class QRCode(val productCode: String) : Barcode

This could then be used in a function such as:

fun barcodeAsString(barcode: Barcode): String =
when (barcode) {
is UPCA -> “${barcode.numberSystem} ${barcode.manufacturer} ${barcode.product} ${barcode.check}”
is QRCode -> “${barcode.productCode}”
else -> “Unknown”
}

But since anything can implement the Barcode interface the compiler is unable to determine if the when statement handles all possible cases so the else is required.

Using a sealed class

Now, if we modify the implementation to use a sealed class it is possible to improve our type safety and remove that extraneous else.

So the example now looks like

sealed class Barcode {
class UPCA(val numberSystem: Int, val manufacturer: Int, val product: Int, val check: Int) : Barcode()
class QRCode(val productCode: String) : Barcode()
}

and

fun barcodeAsString(barcode: Barcode): String =
when (barcode) {
is Barcode.UPCA -> “${barcode.numberSystem} ${barcode.manufacturer} ${barcode.product} ${barcode.check}”
is Barcode.QRCode -> “${barcode.productCode}”
}

The compiler is now able to check that all Barcode types have been catered for in the when statement so the else block is no longer required.

Documentation on sealed classes

--

--