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?
No, we cannot extend an enum in Java. Java enums can extend java. lang. Enum class implicitly, so enum types cannot extend another class.
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 ... } }
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!
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With