Andrew K
06/24/2021, 12:00 AMfind
extension in addition to an Int? Is there anything else I can do to optimize as well?
infix fun <T> T?.ifNull(block: () -> T?) = this ?: block()
inline fun <reified T> EnumCompanion<T>.find(value: Int): T? where T : Enum<T>, T : EnumValue<T> =
enumValues<T>().run {
firstOrNull { (it.value as Int) == value }
.ifNull { firstOrNull { it.name == "Unknown" } }
.ifNull { throw Exception("Enum value does not exist") }
}
interface EnumCompanion<T : Enum<T>>
interface EnumValue<T> {
val value: T
}
enum class MyEnum(override val value: Int) : EnumValue<Int> {
Unknown(0),
First(1),
Second(2),
Third(3);
companion object : EnumCompanion<MyEnum>
}
MyEnum.find(1)
Mranders
09/02/2021, 6:01 PMEnum
type and one for the EnumValue
type. Furthermore, a couple of things:
• Your ifNull
could just be the inbuilt ?:
operator
• The return type is currently T?
, but could be T
, since it will never return null
So, the function could look like this:
inline fun <reified T, V> EnumCompanion<T>.find(value: V): T where T : Enum<T>, T : EnumValue<V> =
enumValues<T>().run {
firstOrNull { it.value == value }
?: firstOrNull { it.name == "Unknown" }
?: throw Exception("Enum value does not exist")
}
From a personal perspective, I would not use the matching on name == "Unknown"
to attempt to find an "Unknown". I would probably have three functions:
inline fun <reified T, V> EnumCompanion<T>.find(value: V): T? where T : Enum<T>, T : EnumValue<V> =
enumValues<T>().firstOrNull { it.value == value }
inline fun <reified T, V> EnumCompanion<T>.findOrError(value: V): T where T : Enum<T>, T : EnumValue<V> =
find(value) ?: throw Exception("Enum value $value does not exist")
inline fun <reified T, V> EnumCompanion<T>.findOrDefault(value: V, default: T): T where T : Enum<T>, T : EnumValue<V> =
find(value) ?: default
And I'm not sure about the third, since the ?:
can already express that at the call site.
If your domain has well defined "defaults" for enumerations, then you could expand the EnumCompanion
to contain it, and then use it - something like this:
interface EnumCompanion<T : Enum<T>> {
val default: T
}
enum class MyEnum(override val value: Int) : EnumValue<Int> {
Unknown(0),
First(1),
Second(2),
Third(3);
companion object : EnumCompanion<MyEnum> {
override val default = Unknown
}
}
inline fun <reified T, V> EnumCompanion<T>.find(value: V): T where T : Enum<T>, T : EnumValue<V> =
enumValues<T>().firstOrNull { it.value == value } ?: default