kotlinx.serialization: Serializer for Nothing not found
Describe the bug
Using Nothing in a generic type argument fails with an internal error Serializer for element of type Nothing has not been found.
To Reproduce This reproduces the problem when compiling:
import kotlinx.serialization.Serializable
@Serializable
sealed class SerializableEither<out L, out R> {
@Serializable
data class Left<L>(val value: L) : SerializableEither<L, Nothing>()
@Serializable
data class Right<R>(val value: R) : SerializableEither<Nothing, R>()
}
Full compiler error: https://pastebin.com/FP6zGrDf
Expected behavior
Nothing should be serializable.
Environment
- Kotlin version: 1.3.60
- Library version: 0.14.0
- Kotlin platforms: JVM
- Gradle version: 5.6.4
- IDE version (if bug is related to the IDE): IntelliJ IDEA 2019.2.4 (Ultimate Edition)
- Runtime version: 11.0.4+10-b304.77 amd64
- Linux 5.0.0-36-generic
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 7
- Comments: 19 (10 by maintainers)
Commits related to this issue
- Added support for the `kotlin.Nothing` class as built-in Resolves #614 Resolves #932 — committed to Kotlin/kotlinx.serialization by shanshin 2 years ago
- Added support for the `kotlin.Nothing` class as built-in Resolves #614 Resolves #932 — committed to Kotlin/kotlinx.serialization by shanshin 2 years ago
- Added support for the `kotlin.Nothing` class as built-in (#1991) Resolves #614 Resolves #932 Co-authored-by: Paul de Vrieze <pdvrieze@users.noreply.github.com> — committed to Kotlin/kotlinx.serialization by shanshin a year ago
I’ve just started using kotlinx-serialization in a new project and this is basically the first issue I came across, with a compiler error that’s not very helpful (location: “File is unknown”).
Having a default serializer for
Nothingwould avoid that, wouldn’t it?I am of the perspective that
Nothingis serializable because it contains no information: serizialing no information should be a trivial task, right? I originally found this problem because I was trying to serialize arrow-kt’s data structures. arrow makes heavy use ofNothingthroughout their data structures; most of them involveNothingin one way or another.@raulraja If you have a different perspective on this, please feel free to contribute it to this discussion.
So it would be basically like this:
Such serializer can be applied for types in generic arguments (
data class Left<L>(val value: L) : SerializableEither<L, @Serializable(NotSerializable::class) Nothing>()).It even can be a default serializer for
Nothing.I think the issue here is not that
Nothingis encodable or not. The issue here is that this isNothingin type argument position. Nothing, bottom type, and subtype of all types can appear anywhere in generic arg in any data structure. For example:Nothingin higher kind position still allows it’s a wrapper to be instantiable if it Nothing appears as the type arg of a covariant argument likeout ANothing itself does not need to be instantiated or serialized because the bottom type has 0 inhabitants.
I think all Serialization needs for this to work with is to ignore
Nothingwhen it appears in type argument position.Revisiting a simple understood example which is object to this problem. One of the Arrow Data types.
A simplified version:
In this example where
Option = Some | Nonethat is a sealed union in order to provide a Serializer, it needs the Serializers ofSome,NoneandA. But it does not need the serializer ofNothingto provide any of the possible values that can be created for an Option.In the case above since
Nothingappears invariant in the receiver value it can ensure impossible values won’t compile.I believe you can support higher kinded
<_ : Nothing>which is the issue at hand by simply treatingNothingin type argument position as a NOOP serializer and keep bailing for properties which specifyNothingdirectly. For example:My bad, yes. I meant parameterised types that use Nothing, which isn’t uncommon.
@rubenquadros The problem here is that you somehow captured a
Voidtype from the Java side. This is not a built in type. Ideally you would avoid theVoidtype entirely, but alternatively you could provide a serializer as a contextual serializer (registered in the module).Perhaps a
NothingSerializerwould be valid if it would indeed refuse to serialize or deserialize (but does exist for type argument reasons). I think the use case is valid and implementing is probably easiest when just creating this “serializer”…