Rob Elliot
10/14/2020, 10:33 AMval x: Int? = null
val xs: Set<Int> = setOf(1, 2, 3)
xs.contains(x) // compiles, but why?
because the type of contains
is public operator fun <@kotlin.internal.OnlyInputTypes T> Iterable<T>.contains(element: T): Boolean
.
Does @kotlin.internal.OnlyInputTypes
mean that `T`is defined by the type of element
not of the receiver? I guess that would type check, as Int
is a subtype of Int?
- right?spand
10/14/2020, 10:44 AMT
is inferred to be the widest of the two types
I think the purpose of T
here is to prevent you checking if Set<Int>
contains something that can never be true ie. a String
Rob Elliot
10/14/2020, 10:45 AMSet<Int>.contains(null: Int?)
can never be true.spand
10/14/2020, 10:47 AMInt
in x
Rob Elliot
10/14/2020, 10:48 AMspand
10/14/2020, 10:48 AMx
and you get the same error as with a String
Rob Elliot
10/14/2020, 11:24 AMT
can resolve to `Any?`:
fun main() {
fun <T> Set<T>.contains2(n: T): Boolean = this.any { it == n }
val int: Int = 1
val nullableInt: Int? = null
val string: String = ""
val nullableString: String? = null
val ints: Set<Int> = setOf(1, 2, 3)
val nullableInts: Set<Int?> = setOf(1, 2, null, 3)
val strings: Set<String> = setOf("1", "2", "3")
val nullableStrings: Set<String?> = setOf("1", "2", null, "3")
ints.contains2(int)
ints.contains2(nullableInt)
ints.contains2(string)
ints.contains2(nullableString)
nullableInts.contains2(int)
nullableInts.contains2(nullableInt)
nullableInts.contains2(string)
nullableInts.contains2(nullableString)
strings.contains2(int)
strings.contains2(nullableInt)
strings.contains2(string)
strings.contains2(nullableString)
nullableStrings.contains2(int)
nullableStrings.contains2(nullableInt)
nullableStrings.contains2(string)
nullableStrings.contains2(nullableString)
}
Nir
10/14/2020, 12:55 PMNir
10/14/2020, 12:56 PMspand
10/14/2020, 1:02 PMcontains2
. Its been years since I had the problem myself but dabbed a bit with the internal Exact
annotation that should prevent this case ( related discussion here https://discuss.kotlinlang.org/t/how-prevent-type-inference/8140/4)spand
10/14/2020, 1:03 PMSet
instead of as an extension method (as far as I can recall)ilya.gorbunov
10/14/2020, 1:23 PMhad the method been specified on the SetIt is: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-set/contains.html
Nir
10/14/2020, 1:25 PMNir
10/14/2020, 1:25 PMilya.gorbunov
10/14/2020, 1:25 PMNir
10/14/2020, 1:26 PMAny
implicitly at the base of every hierarchy is really a blow to type safetyNir
10/14/2020, 1:27 PMNir
10/14/2020, 1:27 PMNir
10/14/2020, 1:27 PMlistOf(1) + listOf("hello")
compiling is a bit of a tragedyilya.gorbunov
10/14/2020, 1:48 PMNir
10/14/2020, 1:58 PMa + b
instead of a + c
), and you don't get a compiler error for itspand
10/15/2020, 5:52 AMcontains
and contains2
in this example are equivalent. But as can be seen in the test()
function they are not. I assume that with the Exact
annotation it would be possible to get the same compiler error for the contains2
usage. Feel free to correct me if it is possible to achieve this without internal type annotations.
interface MySet<out T> {
fun contains(t: @UnsafeVariance T): Boolean
}
fun <T> MySet<T>.contains2(t: T): Boolean {
TODO()
}
fun test(){
val stringSet: MySet<String> by lazy { TODO() }
stringSet.contains2(1) // Not compile error
stringSet.contains(1) // compile error
}