7

I'm implementing a stack algorithm for study purpose in Kotlin

class Stack<T:Comparable<T>>(list:MutableList<T>) {

    var items: MutableList<T> = list


    fun isEmpty():Boolean = this.items.isEmpty()

    fun count():Int = this.items.count()

    fun push(element:T) {
        val position = this.count()
        this.items.add(position, element)
    }

    override  fun toString() = this.items.toString()

    fun pop():T? {
        if (this.isEmpty()) {
            return null
        } else {
            val item =  this.items.count() - 1
            return this.items.removeAt(item)
        }
    }

    fun peek():T? {
        if (isEmpty()) {
            return null
        } else {
            return this.items[this.items.count() - 1]
        }
    }

}

And I'm trying to execute using this code:

fun main(args: Array<String>) {

        var initialValue = listOf<Int>(10) as MutableList<Int>
        var stack = Stack<Int>(initialValue)
          stack.push(22)
        println(stack.count())
        println(stack.isEmpty())
        println(stack.pop())
        println(stack.count())
        println(stack.isEmpty())

    }

When I run the code I receive this error:

Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at Stack.push(Stack.kt:17)
at StackKt.main(Stack.kt:45)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

This is related with the follow line that is implemented in push(element:T) method:

 this.items.add(position, element)

The most weird thing is that I used a very similar code implementing a orderedArray and it works perfectly.

Do you have any idea of what I'm doing wrong ?

2 Answers 2

19

listOf<Int> is not truly mutable. According to the doc:

fun <T> listOf(vararg elements: T): List<T> (source) Returns a new read-only list of given elements. The returned list is serializable (JVM).

You should use mutableListOf<> instead.

The reason why as MutableList is permitted here is because listOf(10) returns Collections.singletonList(10) which returns a java.util.List (which Kotlin assumes implements the kotlin.collections.MutableList interface). So the compiler does not know it's not really mutable until the mutating method is called at runtime and throws the exception.

Sign up to request clarification or add additional context in comments.

5 Comments

So the solution is, in the main method, set initialvalue with mutableListOf instead of listOf, right ?
The explanation why the cast is legal goes as follows: List is an interface and MutableList is an interface that extends List. Therefore casting from List to MutableList is legal but it can and will crash at runtime.
Thanks for the explanation Kirill !
@KirillRakhman That's true that the cast is allowed at compile time, but it is because listOf returns a java.util.List which implements kotlin.collections.MutableList interface. So it does not crash at the cast but rather at the call to add, when the implementation throws an exception.
Kotlin's List and MutableList are both mapped to java.util.List at compile time and don't exist at runtime at all.
8

You can fix this by calling toMutableList() api rather than using smart cast (as).

Try: var initialValue = listOf< Int >(10).toMutableList()

Below is a working example:

fun main(){
    val x : List<String> = listOf("foo", "bar", "baz")
    //val y: MutableList<String> = x as MutableList<String> throws UnsupportedOperationException
    val y: MutableList<String> = x.toMutableList()
    y.add("sha")
    println(y) // [foo, bar, baz, sha]
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.