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