0

I'm struggling with nullable and non-nullable types. There are two errors. I defined a class which implements the "Queue" concept, as follows, trying to make its Generic Parametric Type nullable and here there's the first error:

class QueueLightweight<T: Any?> { //: Queue<T?> removed because of Java clashes, but it's another question
        protected var size = 0
        protected var first: NodeQLW<T>? = null
        protected var last: NodeQLW<T>? = null

        protected class NodeQLW<E>(var item: E) {
            var next: NodeQLW<E>? = null
        }

        ....

        fun iterator(): Iterator<T> {
            return IteratorQLW(this)
        }

        ....

        fun add(e: T?): Boolean {
            val n: NodeQLW<T>
            n = NodeQLW(e) // <--- first error: 
            // "type inference failed: required: QueueLightweight.NodeQLW<T> , found: QueueLightweight.NodeQLW<T?> "
            if (size == 0) {
                last = n
                first = last
                size = 1
            } else {
                last!!.next = n
                last = n
                size++
            }
            return true
        }
    }

I then defined an Iterator subclass as follows, and in the highlighted line (by an arrow), there's the error.

protected class IteratorQLW<E: Any?>(var q: QueueLightweight<E>) :
Iterator<E> {
var n: NodeQLW<E>?
init {
    n = q.first
}

override fun hasNext(): Boolean {
    return n != null
}

override fun next(): E {
    var e: E
    e = null // <--- error here: null cannot be a value of a non-null type E
    if (n != null) {
        e = n!!.item
        n = n!!.next
    }
    return e
}

}

I don't understand how to fix those errors.

Marco Ottina
  • 399
  • 5
  • 12

2 Answers2

2

The type allows nullable by default, so your class type definition can just be <T>, not <T: Any?>. A generic type can be assigned as non-nullable when the class is used (such as using QueueLightweight<String> instead of QueueLightweight<String?>), so you have to treat it like it could be non-nullable when you are working with the generic type inside the class.

This is the source of your first problem. Your NodeQLE is expecting a possibly non-nullable parameter for its constructor, but you are forcing it to be null.Your add method should take a T parameter, not enforced T?.

Then in your iterator you declare a variable as (possibly) non-nullable E, but assign a null to it. You would need to make the variable nullable. Since it can return null even if E is non-nullable, you have to throw an exception if there is no next value. But this can be simplified by changing the branching, so the method should look like this:

override fun next(): E {
    n?.let {
        n = it.next
        return it.item
    }
    throw NoSuchElementException()
}
Tenfour04
  • 83,111
  • 11
  • 94
  • 154
1

Non-nullable types are subtypes of corresponding nullable types. E.g. any String is a String? and thus String is a subtype of String?. So any type at all, including non-nullable types, is a subtype of Any? and E: Any? bound doesn't force E to be nullable (and can be removed).

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487