for a “problem” like this where you are not sure how negatively performance is impacted and you want to give yourself that extra bit of misguided reassurance that you am somehow smarter than the JIT compiler at optimization, you can use inline class
in kotlin.
An inline class
is similar to a data class in that it must have a property parameter. The difference is that it must have only one single parameter and it must be a val
. An inline class
can also not have any “concrete properties” in that it cannot have anything like this val memberOfInlineClass: Type = Type("data")
and it must use custom getters instead.
This idea I am about to explain is where inline class
gets it’s supposed power. inline class
is optimized as it’s val
parameter type because it is essentially that type and all your functions inside of it will have to rely on this parameter to get their functions. If you are using an inline class
as itself and not any potential interfaces it implements, ti will be optimized at that type. If you use it as any of it’s interfaces OR as a nullable, it will NOT be optimized and will be “boxed”. You CANNOT use it as it’s underlying type. Calls to any of the properties or functions will be inlined to the call site.
Here’s an example of some code I use which I hope you will be able to use as an example to “fix” your “problem” as I think your code could do something similar to mine and could benefit from using inline class
fun Int.getByte(byteIndex: Int): Byte { /* code to get the byte here */ }
fun Int.replaceByte(byteIndex: Int, value: Byte): Int { /* code to replace the byte here */ }
interface HasAlphaChannel {
val alpha: Int
}
interface RGBColor {
val red: Int
val green: Int
val blue: Int
}
// This will be optimized as an Int when used as an ARGB8 but NOT as ARGB8? RGBColor or HasAlphaChannel.
inline class ARGB8(val channels: Int): RGBColor, HasAlphaChannel {
constructor(
alpha: Byte,
red: Byte,
green: Byte,
blue: Byte
): this(
0x00000000
.setByte(0, alpha)
.setByte(1, red)
.setByte(2, green)
.setByte(3, blue)
)
override val alpha: Int get() = channels.getByte(0).toInt()
override val red: Int get() = channels.getByte(1).toInt()
override val green: Int get() = channels.getByte(2).toInt()
override val blue: Int get() = channels.getByte(3).toInt()
}
fun main() {
val transparentSwamp = ARGB(64, 0xE0, 0x77, 0x77)
}