Hey all, I'm not sure if this is the right place f...
# arrow
n
Hey all, I'm not sure if this is the right place for this, as it's kind of a design/ecosystem question -- but I'm looking for the perspective of the FP community programming in Kotlin. I've started experimenting with kotlinx.serialixation recently -- and at first it seemed really promising -- kind of like an ad hoc implementation of a type-class approach to serializers/deserializers, implemented as a compiler plugin. It kind of reminds me a lot of Rust's serde in that sense as well, as it supports a number of different output formats from a single "type-class". This seems to work well, and how I would expect for sealed classes/data classes, but I am confused by the kotlinx.serialization team's decisions regarding the behavior of serializing interfaces. Apparently, interfaces are automatically serializable via "polymorphic serializers" that are registered at run-time. In other words, if I have a data class with a member that is an interface, unless I register a polymorphic serializer (or otherwise manually specify a serializer with
@Serializable(with=...)
), serialization of my data class will fail at run-time, instead of warning me at compile-time that my data class is not serializable. Coming from experience with type-class/trait based approaches to serialization, this is really jarring to me in practice. One of the nice things to me about automatically deriving serializer/deserializers pairs is that it eliminates a whole class of unit/property-based tests I would otherwise have to write to ensure correctness of my program. If there's a possibility my program could crash at run-time because I tried to serialize something that isn't serializable, I still need to write those tests, which can be very tedious/time consuming. However, when I asked a question and suggested at least allowing for users to "opt-out" of the "interfaces are automatically serializable" approach", I got the response: "Open polymorphism is a powerful mechanism that is tied to the runtime by its nature, so giving up on compile-time errors is a tradeoff for convenience." So, I have a couple of questions for the community here: 1. Does anyone understand this design decision, and exactly why this decision from the kotlinx.serialization team is convenient? 2. Is anyone else equally bothered as me from the lack of compile-time type safety in the current implementation of kotlinx.serialization? For 2, perhaps if there is enough support we could open a new feature request specifically asking to be able to opt out of automatic interface serialization at run-time. If the Kotlin team holds to their grounds, there's always the possibility that someone could make a fork, or a more properly type-class based approach, but I'd like to avoid that if possible. Less fragmentation is good!
s
Hey Nathan, People that care about about statically typed FP will always want full compile-time type safety. There are some other projects out there that offer more compile-time safety, but they all come at the cost of more boilerplate rather than something like type-classes / Generics to auto-derive/inject instances. KotlinX Serialization has this limitation because afaik it basically ignores generic (which is what introduces the possibility to runtime errors). So they only offer partial compile-time safety. In Arrow Meta we’ve been experimenting with Generic derivation, and function based injection/proofs. Feature that offer ad-hoc polymorphism like type-classes. Nothing concrete yet though, except a Generic proposal PR here: https://github.com/arrow-kt/arrow It should also be possible to write compiler plugin that adds support for compile-time safety on top of KotlinX Serialization, and I guess automatically implement a static
Json
object with the correct factories since in the actual runtime it will still use reflection rather than statically injected instances.