Ah, I wasn’t judicious in my quoting. What I meant was example of “warts”. Like you said you can’t cast or perform instanceof
. Reflection is also out.
Putting the extension method in the companion object is definitively judicious.
For linked list, I would have started like this:
import java.util.Collections
sealed class List<T>: Iterable<T>
{
abstract fun isEmpty(): Boolean
// more abstract methods
class Cons<T> (val head: T, val tail: List<out T>): List<T>()
{
override fun iterator(): Iterator<T> {
return object: Iterator<T> {
var node: Cons<out T> = this@Cons
override fun hasNext() = !node.isEmpty()
override fun next() = node.head.apply { node = node.tail as Cons<out T> }
}
}
override fun isEmpty() = true
// implement more abstract methods
}
object Nil: List<Nothing>() {
override fun iterator() = Collections.emptyIterator<Nothing>()
override fun isEmpty() = true
// implement more abstract methods
}
}
fun <T> List(vararg elems: T): List<out T>
= elems.foldRight<T, List<out T>>(List.Nil, { h, t -> List.Cons(h, t) })
val list = List(1, 2, 3, 4)
I’m not super convinced about needing an interface for linked list (your IList
), it’s a bit specific. Also it’s rather too fat for my taste. Maybe make some of these interface methods extension methods instead*. At least consider giving them a default implementation.
(*) Although in that case they can’t be overriden in favor of a more efficient implementation. I would love a mechanism to be able to add dynamically dispatched methods to classes, which would alleviate this problem.
Dropping the interface also lets you use nice vals for head and tail.
As an aside, the type inference on foldRight
was pretty nasty. I would have liked to write:
fun <T> List(vararg elems: T): List<out T> = elems.foldRight(List.Nil, ::List.Cons)
but ::List.Cons
is a syntax error, and the type inference couldn’t figure out the types, which doesn’t seem right in this rather straightforward case. Casting List.Nil
to List<out T>
makes inference work. Replacing it by the nonsensical List.Cons(null as T, List.Nil)
also makes inference work.