Auto-casting not working for lists

#1

The following code should be self explaining. I’ve got a list of Test objects, the function test get’s a downcasted test object supplied. Since list can only have test objects, the object must be a Test. But kotlin doesn’t recognize this.

val list = mutableListOf<Test>(Test())

fun main() = test(list[0])

fun test(obj: Any) {
    if (obj in list) { // No auto casting :c
        obj.print() // Fails
        (obj as Test).print() // Workaround
    }
}

class Test {
    fun print() = println("Hello World!")
}
#2

You should check type before.

MutableList<Test> can be cast to Iterable<Any>.
The type of obj is Any, so obj in list equals to list.contains<Any>(obj).

You can see that the contains method below not the same.

image

#3

Anything can be cast to Any. MutableList should (is intended to) only contain Test objects, so when the list contains an object, it should be Test.

#4

The contains method your called is not belong to List.

#5

And? This doesn’t change anything. When an object is in MutableList<Test> then the object is Test.

#6

The Kotlin compiler simply doesn’t know that List<T>.contains(x) == true implies that x is T. I’m sure that could be somehow added with contracts, but currently, the compiler only recognises simple conditions and casts like is, as? and so on.

#7

I was pretty sure that constraints are already used in the stdlib for things like this. Seems like i was wrong. Thanks for the clarification tho.

#8

The reason why contains does not yet use contracts is that it’s a member function of List and contracts only work for top level functions right now. I guess this will be added once contracts are expanded to work with member functions.

#9

Okay, I hope they will fix this when constracts are stable.