Say we want to implement trees in the spirit of abstract data types. This works fine:
sealed class Tree() {
data class Node(var value: Int,
var left: Tree = None,
var right: Tree = None): Tree()
object None: Tree()
}
However, if we want to make Tree generic, we get into trouble:
sealed class Tree<T>() {
data class Node<T>(var value: T,
var left: Tree<T> = None,
var right: Tree<T> = None): Tree<T>()
object None: Tree<???>()
}
We can’t leave out the type parameter for None, so what to put there?
-
We can not make
Nonegeneric. -
Nothingonly works if we declareTree<out T>and make the tree immutable. That’s fine for some use cases, but not for others.sealed class Tree<out T>() { data class Node<out T>(val value: T, val left: Tree<T> = None, val right: Tree<T> = None): Tree<T>() object None: Tree<Nothing>() } -
We can make
Nonea (generic) class. That creates lots of instances that we would hope to avoid.sealed class Tree<T>() { data class Node<T>(var value: T, var left: Tree<T> = None(), var right: Tree<T> = None()): Tree<T>() class None<T>: Tree<T>() }
Of course, we could in this case change the design and use optional left/right together with Leaf instead of None (or a larger list of “cases”). The general issue/question remains, though.
Is there a way, ideally idiomatic, to go about modelling singletons in invariant generic sealed classes?
PS: It seems ironic that the JVM would be perfectly happy with None having basic type Tree, if I’m not missing something.
PPS: I’m not sure what kind of questions would be more at home on SO. Please advise.