https://kotlinlang.org logo
#serialization
Title
# serialization
j

Jan Skrasek

11/29/2023, 9:19 AM
Hi, is there somewhere a design document on the main arch - e.g., having
@Serializable
annotation contrary to Swift's interface (
Codable
). I face some unpleasant limitations that would be solvable that way and I'd love to read about it more.
a

Adam S

11/29/2023, 9:22 AM
I'm not sure if your answer will be here, but you could try looking through the KEEP https://github.com/Kotlin/KEEP/blob/master/proposals/extensions/serialization.md and the discussion https://github.com/Kotlin/KEEP/issues/149
j

Jan Skrasek

11/29/2023, 9:37 AM
I saw the KEEP but the issue may have more info I'm looking for 🙂 thx
fist bump 1
c

CLOVIS

11/29/2023, 9:40 AM
Just a guess, but the annotation is not actually necessary. All it does is instruct the compiler to generate the serializer, but you could generate them by hand without ever using the annotation. That's quite important because it means you can create serializers for classes from other modules / that you don't control, for example if you want to serialize a type from a library that doesn't have KotlinX.Serialization support. I don't think this would be possible if it was an interface. Also, (but I could be completely wrong, I don't know much about Swift), I think you can declare static methods in interfaces, that can be overriden by classes. This allows declaring factory-like static methods, that each implementation can override to call its own constructor. This is not possible in Kotlin, so the serializer has to be a different object.
j

Jan Skrasek

11/29/2023, 9:45 AM
Well, the most problematic part is that I cannot design build-time safe API that takes everything that is serializable. Of course, it make sense that the core serialization library would have to have both apis: •
serialize(value: Serializable)
<T> serialize(value: Any, serializer = serializer<T>())
But if I'm building just the private code, having an option to limit the accepted type would be awesome.
Most importantly, this is super needed with open polymorphism. Let's say I have an interface and I need all its implementations to be serializable. The API design is very limited: • only runtime checks - bad • sealed polymorphism - impossible for multimodule • open polymorphism - manual/pseudoautomatic building of the serialzable module
c

CLOVIS

11/29/2023, 9:47 AM
That's true, but it's also not possible to know at build time which objects are serializable or not, because you can register serializers at execution-time (documentation).
j

Jan Skrasek

11/29/2023, 9:47 AM
Defining
interface TrackingEvent : Serializable
would "solve" it quite nicely 🙂
but it's also not possible to know at build time which objects are serializable or not
Yes, I'd consider this an optional feature - if you know this, you can have a build-time check. Anyway, that's why it would be needed to keep the API we have rn. (apart from the bc).
a

Adam S

11/29/2023, 10:14 AM
perhaps what you're really looking for is a way to 'disable' the reified serialize extension function so that you'd be forced to always pass in a serializer? It would be more verbose, but it would be compile-time safe.
☝️ 1
j

Jan Skrasek

11/29/2023, 10:19 AM
Well, I definitely don't want everyone to pass the serializer manually. But even if I would, then: Let's take a look at something like
interface Destination : Serializable
. Ideally, I want to expose the
Flow<Destination>
from VM - but that wouldn't be enough, I'd have to expose
Flow<Pair<Destination, KSerializer<...>>
- that's beginning to be enormously complex and overcomplicated.
a

Adam S

11/29/2023, 10:21 AM
good point
a

Arkadii Ivanov

11/29/2023, 1:16 PM
> Well, the most problematic part is that I cannot design build-time safe API that takes everything that is serializable. I had this question when converting my libraries from Parcelize to kotlinx-serialization. I resolved it by letting my APIs accept
KSerializer
explicitly. E.g. something like the following:
Copy code
fun <T : Any> someApi(
    value: T,
    serializer: KSerializer<T>,
    ...
)
For example the Decompose library uses this approach to save and restore the navigation stack.
☝️ 1