kotlinx.serialization icon indicating copy to clipboard operation
kotlinx.serialization copied to clipboard

Gradually stop in-place serializing value classes to prepare for multi-value value classes

Open rnett opened this issue 1 month ago • 4 comments

What is your use-case and why do you need this feature?

Currently, kotlinx.serialization serializes all value classes as their property type. This works since only single-property value classes are supported. However, this is temporary, eventually multi-property value classes will be supported.

Serializing single-property and multi-property value classes differently in this way would be extremely unexpected and unintuitive.

Describe the solution you'd like

Value classes (the existing single-arg versions) should gradually stop being serialized in-place. This should be a gradual, backwards, compatible migration, like e.g. data class consistent copy visibility. Presumably that would mean first introducing an annotation to serialize non-in-place, then gradually deprecating it and making the behavior the default.

While this could in theory be based on @JvmInline, I don't think it's a good idea, since that's an implementation detail about how the class is represented, and doesn't really have any tie to the serial format. I also have no idea what the future of that annotation is in a post-Valhalla world. But I wouldn't want, for example, to not be able to migrate to using Valhalla single value value classes because I need this annotation for serialization.

Serializing in-place can be useful sometimes, it would be nice if there was an annotation to retain this behavior long term. At least for single-value value classes (although I see no reason to tie it to value classes).

rnett avatar Oct 31 '25 00:10 rnett

While I agree that it would be good to be able to configure the behaviour, it is actually possible to handle multi-value classes as inline, as long as the used element names are unique across the container/value element. It does however require more complexity on the decoding part as the decoder must (for non-single-element value children) memorize the parsed values until either all have been parsed or the outer element is fully parsed (to then present them to the value deserializer).

In line with that I think it is better to support single-element value classes as current (and determined by the format). There should be an annotation (either global or per format) to allow specifying the behaviour (both at type level and use site), and probably format configuration options for the default.

Beyond that, it might be worthwhile to have infrastructure for incremental parsing (a significant extension on what serializers do), that would (better) support parsing of composite inline values, as well as being able to be used to support the incremental parsing of collections (in a more general/user definable way). I might have a stab at that.

pdvrieze avatar Oct 31 '25 10:10 pdvrieze

I'm indeed planning to rely on @JvmInline for those purposes. As far as I recall the current proposal (@ice-phoenix PTAL), new value classes will be significantly different from current ones, supporting both Valhalla and deep immutability. So @JvmInline annotation will likely affect many more things than just serialization.

sandwwraith avatar Nov 03 '25 10:11 sandwwraith

I probably do not have enough context to give a definite answer, but from my point-of-view how we serialize (multi-field) value classes is almost orthogonal to them being or not being value classes. I could totally see serializing "new" value classes with a single field in-place, or the "old" inline value classes with an extra level of indirection.

In other words, I definitely do not agree with the statement of "Serializing single-property and multi-property value classes differently in this way would be extremely unexpected and unintuitive", I would say any serialization library (kotlinx.serialization included) should be free to choose whichever default they prefer.

I would even say that serializing single-property value class in-place is a reasonable default even for the "new" (non-@JvmInline) value classes.

ice-phoenix avatar Dec 02 '25 17:12 ice-phoenix

@ice-phoenix Ideally it would be a per-format decision, although for most it will come with some restrictions (as above), from my perspective maintaining the XML format I would want sufficient information to make the decision. But you are right, having serialization collapse types (omitting the container) is orthogonal to whether they are inline at runtime.

pdvrieze avatar Dec 02 '25 21:12 pdvrieze