Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to extend enums in Kotlin?

Tags:

enums

kotlin

In my Kotlin project, I have a DefaultError enum

enum class DefaultError {
    INTERNET_ERROR,
    BLUETOOTH_ERROR,
    TEMPERATURE_ERROR
}

I would like to extend them so that I have

enum class NfcAndDefaultError : DefaultError {
    //DefaultError inherited plus
    NFC_ERROR
}

and another enum

enum class KameraAndDefaultError : DefaultError {
    //DefaultError inherited plus
    CAM_ERROR
}

Now, I have

enum class NfcDefaultError {
    INTERNET_ERROR,
    BLUETOOTH_ERROR,
    TEMPERATURE_ERROR,
    NFC_ERROR
}

and

enum class KameraAndDefaultError {
    INTERNET_ERROR,
    BLUETOOTH_ERROR,
    TEMPERATURE_ERROR,,
    CAM_ERROR
}

I bet Kotlin has a nice way there?

like image 255
Noam Silverstein Avatar asked Jun 25 '19 08:06

Noam Silverstein


People also ask

Can enums be extended?

No, we cannot extend an enum in Java. Java enums can extend java. lang. Enum class implicitly, so enum types cannot extend another class.

How do I add value to an enum in Kotlin?

So just put the constants into your own non-companion object: object StatusFlags { const val COMPLETE_INT = 0 const val RUNNING_INT = 1 const val WAITING_INT = 2 } fun Status. flag(): Int { when(this) { RUNNING -> return StatusFlags. RUNNING_INT ... } }


1 Answers

There is more to the reason why enum inheritance is not supported than "inheritance is evil". In fact, a very practical reason:

enum class BaseColor { BLUE, GREEN, RED }

val x: BaseColor = ... // must be one of the 3 enums, right?
// e.g. when {} can be done exhaustively with BLUE, GREEN, RED

enum class DerivedColor : BaseColor { YELLOW }

val y: BaseColor = ... // now, it can also be YELLOW
// here, you lose the guarantee that it's a value in a limited set
// and thus the main advantage of enums

There are multiple options to achieve what you like:

1. Different enums implement a common interface

I would refer you to this answer.

Interfaces are a very flexible solution and allow you to derive an unlimited number of enums. If this is what you need, go for it.

2. Sealed classes

In Kotlin, sealed classes are a generalization of enums, that allows you to retain state in each value. All derived classes of a sealed class must be known up-front and declared in the same file. The advantage compared to interfaces is that you can limit the sealed class to a fixed set of possible types. This allows you to omit the else branch in when, for example. The drawback is that it's not possible to add types outside the sealed class by design.

Semantically, you have an enum of enums: the first level determines which enum class type is used, and the second level determines which enumerator (constant) inside that enum class is used.

enum class DefaultError { INTERNET_ERROR, BLUETOOTH_ERROR, TEMPERATURE_ERROR }
enum class NfcError { NFC_ERROR }
enum class CameraError { CAM_ERROR }

sealed class Error {
    data class Default(val error: DefaultError) : Error()
    data class Nfc(val error: NfcError) : Error()
    data class Camera(val error: CameraError) : Error()
}

fun test() {
    // Note: you can use Error as the abstract base type
    val e: Error = Error.Default(DefaultError.BLUETOOTH_ERROR)

    val str: String = when (e) {
        is Error.Default -> e.error.toString()
        is Error.Nfc -> e.error.toString()
        is Error.Camera -> e.error.toString()
        // no else!
    }
}
like image 61
TheOperator Avatar answered Sep 20 '22 18:09

TheOperator