0

I am trying to implement a parameterized Queue backed by an Array. Just a simple exercise to get more fluent with generics in Kotlin:

class Queue<T>(val size: Int = 1000) {
    private var count = 0
    private var front = 0
    private var back = 0
    private val queue = Array<Any?>(size) { null } // Here's what's bugging me

    fun enqueue(new: T) {
        if (count >= size) throw Exception("Queue is full")
        queue[back] = new
        back = if(back == size-1) 0 else back+1
        count++
    }

    @Suppress("UNCHECKED_CAST")  // And I don't like this
    fun dequeue(): T? {
        if (isEmpty()) return null

        val res: T = queue[front] as T
        front = if (front == size-1) 0 else front+1
        count--

        return res
    }

    @Suppress("UNCHECKED_CAST")
    fun peek(): T? {
        return if (isEmpty()) null else queue[front] as T
    }

    private fun isEmpty() = count == 0
}

This compiles and runs (but I'm wary):

fun main() {
    val queue = Queue<Int>(size = 2)

    queue.enqueue(4)
    queue.enqueue(5)

    println(queue.peek())    // 4
    println(queue.dequeue()) // 4
    println(queue.peek())    // 5

    queue.enqueue(6)
    queue.enqueue(7)    // Exception: Queue is full
}

I'm pretty confident that this implementation is safe and functional, but I really don't like suppressing the UNCHECKED_CAST inspection (nor do I want to leave the warnings).

I have read documentation and articles about generics, and I think I'm following the concepts. But nobody seems to be trying to do anything like this in the examples I've found. I would prefer to make my member queue an Array<T?>, but I understand that at runtime, T won't be known because of Type Erasure.

Is there a better way to do this? Or is it better not to do? Would this raise red flags if I did this in an interview?

Adin
  • 61
  • 1
  • 3
  • I realize the title doesn't quite make sense. The compiler is clearly telling me I can't "back a parameterized class with a parameterized collection." But I want to, and this is as close as I could get. Should I want to? – Adin May 01 '21 at 01:13
  • 1
    [Possible duplicate](https://stackoverflow.com/questions/41941102/instantiating-generic-array-in-kotlin) – Sweeper May 01 '21 at 01:17
  • Suppressing the warning is the correct way to handle this if you've checked the logic yourself. There's no way to avoid it because of type erasure. `@Suppress("UNCHECKED_CAST")` appears in the Kotlin standard library over 100 times. You could alternatively use a `MutableList` instead of an Array, because List types aren't reified. But if you do, you'll have to replace your `as T` with `!!`. Or you could cast your array to `Array` at the declaration site to limit your suppression to one spot and keep it lighter weight than MutableList, but you'd still need the `!!`. – Tenfour04 May 01 '21 at 02:03
  • Thanks, @Tenfour04. That makes sense. List types not being reified is a new concept to me, so I'll dig into that more. But I do prefer casting the member array to `Array` and limiting the casting/suppression to one place. It's also good to know that this is done (I'm sure very carefully) in stdlib. I'm inclined to think I'm writing non-idiomatic code if I have to struggle against the language to do something, but clearly it is unavoidable in some cases. – Adin May 01 '21 at 21:01

0 Answers0