Joris PZ
12/20/2020, 7:57 AMenum class OpCode(val code: Int) {
QUERY(0), IQUERY(1), STATUS(2), NOTIFY(4), UPDATE(5), UNSUPPORTED(-1);
}
fun Int.toOpCode(): OpCode {
return OpCode.values().find { it.code == this } ?: OpCode.UNSUPPORTED.also {
log.error { "Unsupported DNS OpCode $this" }
}
}
This uses a receiver function, which I like in general, and obviously there are many different ways of writing this function (such as fun toOpcode(code:Int): Opcode
) etc.
Now, it occurred to me that this is also possible:
enum class OpCode(val code: Int) {
QUERY(0), IQUERY(1), STATUS(2), NOTIFY(4), UPDATE(5), UNSUPPORTED(-1);
companion object {
operator fun invoke(code: Int): OpCode {
return values().find { it.code == code } ?: UNSUPPORTED.also {
log.error { "Unsupported DNS OpCode $this" }
}
}
}
}
This allows the caller to map an Int
to an OpCode
using what looks like a constructor: val code = OpCode(0)
What would you say if you saw this in a pull request? Is this clever and nice, or horrible and confusing and just showing off? I keep switching sides myself... 🙂Milan Hruban
12/20/2020, 9:22 AMInt
means it's available on every integer, but probably doesn't make sense most of the time. The other approach would just confuse me, because I would think I am instantiating something.
I would go with fun of(code: Int): OpCode
in the companion object, resulting in call like this: val code = OpCode.of(0)
Joris PZ
12/20/2020, 9:42 AMMatteo Mirk
12/21/2020, 9:18 AMMatteo Mirk
12/21/2020, 9:26 AMinline fun <T> List(
size: Int,
init: (index: Int) -> T
): List<T>
not a companion but a top-level function. Gets the job done while simulating a ctor, I think it’s a nice trick and perfectly reasonable if you didn’t know how it’s implemented. The same could apply to your enum: who cares if it’s emulating a ctor, as long as it works and reads clearly? In Java we were forced to use static factory methods, but in Kotlin we have more choices.Milan Hruban
12/21/2020, 10:29 AMprivate
function, then I would also probably choose extension, but I doubt that. What's the difference in having to be explicitly imported? It still pops up in autocomplete (and automatically adds the import, if you select it, likely without you noticing).Matteo Mirk
12/21/2020, 12:01 PMMilan Hruban
12/21/2020, 12:09 PMJoel
12/21/2020, 3:11 PMtoOpcode
but IntelliJ will let you know every potential extension function on an Int
, making it seem like it's available everywhere, when technically it isn't.Joel
12/21/2020, 3:12 PMinvoke
because it results in behavior that is different from what is expected. I'd use the of
pattern and the extension function for ease-of-use i.e.
fun Int.toOpCode() = OpCode.of(this)
Milan Hruban
12/21/2020, 3:35 PM