An snippet of what I'm trying to do: ``` interface...
# announcements
n
An snippet of what I'm trying to do:
Copy code
interface SerializationAdapter<T : Any> {
    fun serialize(obj: T, output: ByteBuf)
    fun deserialize(input: ByteBuf): T
}
data class PacketDeclaration<T : Packet>(val id: Int,
                                                                       val clazz: KClass<T>,
                                                                       val serializer: SerializationAdapter<T>)
interface PacketRegistry {
    fun <P : Packet> resolve(clazz: KClass<P>): PacketDeclaration<P>
}
fun serialize(byteBuf: ByteBuf, packet: Packet) {
    val registry = ...
    val dec = registry.resolve(packet::class)
   dec.serializer.serialize(packet, byteBuf)
   // ^^ Out-projected type 'SerializationAdapter<out Packet>' prohibits the use of 'public abstract fun serialize(obj: T, output: ByteBuf): Unit defined in de.nyxcode.dmn.protocol.SerializationAdapter
}
Any recommendations?
d
Add a type parameter
<T : Packet>
to
serialize
and make
packet
a
T
. Then add a parameter
KClass<T>
. Then make a 2nd version of serialize:
inline fun <reified T : Packet> serialize(buf: ByteBuf, packet: T) = serialize(buf, packet, T::class)
.
👍 1
Of course this will only work if
serialize
is called with known values of
T
. If at the call-site for
serialize
you just have a
Packet
, then this won't help.
n
Interresting approach, thanks!
Just found out that this would work too:
Copy code
(registry.resolve(msg::class) as PacketDeclaration<Packet>).serializer.serialize(msg, out)
d
That's avoiding it though and it's ugly 😛
n
:L Again, thanks for your help!
d
But I am not sure how to solve this better, either.
g
Copy code
Out-projected type 'SerializationAdapter<out Packet>' prohibits the use of 'public abstract fun serialize(obj: T, output: ByteBuf): Unit defined in de.nyxcode.dmn.protocol.SerializationAdapter
this is a covariance warning, Its akin to you trying to writing
Copy code
interface Vehicle; class Car: Vehicle; class Truck: Vehicle

val list: ArrayList<Vehicle> = newCarList() //returns ArrayList<Car>
list.add(new Truck()) //blam
If you change to
Copy code
val list: ArrayList<out Vehicle> = ...
then the line
Copy code
list.add(new Truck())
will fail with the same compiler error your seeing. The type system is trying to tell you that it cannot be certain T is a Packet, and thus passing in a packet might cause heap pollution.
When working with dyanmic class instances I almost always simply drop the static type system's generics, reduce everything to star-projections, and then insert runtime type checks as appropriate. you might consider throwing in a couple
assert(clazz.isInstance(paramOrReturnValue))
👍 1
n
I agree - generics are a pain in the *. Also, I think that generics in Kotlin are even worse than in Java... Kotlin may have fixed the problem @groostav pointed out, but made it far harder to write generic code. Pretty sad, the rest of the language is awesome.. '_'