Say I want to declare a simple algebraic datatype for integer lists:
sealed class IntList
data class Cons(val head: Int, val tail: IntList): IntList()
data class Nil() : IntList()
However, the last declaration results in an error
Data class must have at least one primary constructor parameter
Is it possible to express nullary constructors without having to write lots of boilerplate code? If I change the last declaration to something like
sealed class Nil() : IntList()
then I lose the free implementations of hashCode()
and equals()
that come for free with data class
declarations.
EDIT
Alex Filatov gave a nice short solution below. Obviously, you never need more than one instance of Nil
, so we can just define a singleton object
object Nil : IntList()
However, what would we do if our lists were parameterized by a type parameter? That is, now the first two lines of our definition would be
sealed class List<A>
data class Cons<A>(val head: A, val tail: List<A>): List<A>()
We cannot declare a polymorphic singleton Nil
object which derives from List<A>
for any A
, since we have to provide a concrete type for A
at the time of declaration. The solution (taken from this post) is to declare A
as a covariant type parameter and declare Nil
as a subtype of List<Nothing>
as follows:
sealed class List<out A>
data class Cons<A>(val head: A, val tail: List<A>): List<A>()
object Nil : List<Nothing>()
This allows us to write
val xs: List<Int> = Cons(1, Cons(2, Nil))
val ys: List<Char> = Cons('a', Cons('b', Nil))
Because data class
without data doesn't make sense. Use object
for singletons:
object Nil : IntList()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With