Is there any way to mark a generic type parameter ...
# serialization
e
Is there any way to mark a generic type parameter as being serializable? So that I can do something like:
Copy code
class Test<T>(val t: T) {
  val serializer = T::class.serializer() // I know this doesn't work
}
e
there’s a helper function
serializer<T>()
in the serialization library
no marking necessary, it just crashes if you call it on a non-serializable type
import kotlinx.serialization.serializer
to be specific about where it lives
e
The problem there is that the type for
serializer()
is reified, so I can't use
T
for that.
e
can you ask the caller to give you the serializer?
Copy code
class Test<T>(val t: T, private val serializer: KSerializer<T>)
inline fun <reified T> Test(t: T) = Test(t, serializer())
e
I could, but then I wouldn't need to call
serializer()
. I figured there isn't a way to do this because of erasure, but I wanted to check just to make sure I didn't miss anything.
I suppose I could do something like:
Copy code
inline fun <reified T> Test(t: T) = Test(t, serializer())
 
class Test<T> private constructor(val t: T, private val serializer: KSerializer<T>)
Well that doesn't help in my actual use case (which is a super class constructor), so I guess I'm out of ideas
e
can you post an example that’s closer to your actual use case?
e
Copy code
abstract class Node<State>(initialState: State) {
 private val currentState = MutableStateFlow(initialState)

 private val serializer: KSerializer<State> = // what goes here

 // StateSerializer takes State and KSerializer and serializes to a ByteArray
 fun serializeCurrentState(stateSerializer: StateSerializer) = stateSerializer.serialize(currentState.value, serializer)
}
The caller of
serializeCurrentState
doesn't know what
State
is.
I know I can pass the
KSerializer
to the constructor, but I'm trying to keep the API as simple as possible.
e
maybe take care of it wherever it's instantiated? e.g.
Copy code
abstract class Node<State>(initialState: State) {
    protected abstract val serializer: KSerializer<State>
}
class NodeImpl(initialState: State) : Node<State>(initialState) {
    override val serializer: KSerializer<State> get() = State.serializer()
}
there's really not a great option otherwise. you could do something like
initialState::class.serializer()
, but there's cases where that won't work, such as if the type has generics or if it needs serializers registered in a module
e
I tried something like
initialState::class.serializer()
but it couldn't find that function. I'm assuming it's because
State
is erased to
Any
I'll probably have to go with either: 1. Making it nullable in the super class and allow the subclass to override it. Pro is that subclasses that don't need it can ignore it, con is that it's less discoverable 2. Make it abstract. Pro and con are inverse of above
I would choose to make it abstract. if you have some subclasses where it should be optional, make them inherit from a different base class.
👍🏾 1
e
Thanks for the info (not sure why that function didn't show up for me). I have some thinking to do now 😁