Alex Schiff
04/26/2024, 12:58 PMdmitriy.novozhilov
04/26/2024, 1:17 PMAlex Schiff
04/26/2024, 1:20 PMdmitriy.novozhilov
04/26/2024, 1:28 PMclass Box<T>(var x: T)
fun test(b: Box<*>) {
val a: Any? = b.x
b.x = "hello" // unsafe, error
}
fun main() {
val box = Box(1)
test(box)
}
Inside function test
you don't know which exact Box
was passed inside
So the type of b
is actually Box<Captured(*)>
Captured(*)
means that it is some type which can be passed outside. It may be Int
, it may be String
, it maybe anything.
So when you try to read b.x
it will return this Captured(*)
, which getting approximated to Any?
(as there are no bounds which reduces the set of possible types for it)
But if Captured(*)
stands in input position (like in setter method or when you just assign something to property of such type), there is actually no any reasonable type for it
You can't assign String
to b.x
, as at call site you can pass Box<Int>
You can't assign Int
to b.x
, as at call site you can pass Box<String>
Alex Schiff
04/26/2024, 1:31 PMAlex Schiff
04/26/2024, 1:31 PMdmitriy.novozhilov
04/26/2024, 1:33 PMBox
is not kotlin class but java class with getter and setter instead of property
There was a bug which allowed to write something to such synthetic property, which may lead to runtime exceptions:
public class Box<T> {
public Box(T x) {this.x = x;}
private T x;
public T getX() {return x;}
public void setX(T x) {this.x = x;}
}
fun test(b: Box<*>) {
b.x = 10
}
// compiles with K1
fun main() {
val box = Box("hello")
test(box)
box.x.length // ClassCastException
}
dmitriy.novozhilov
04/26/2024, 1:34 PMfun test(b: Box<*>) {
@Suppress("UNCHECKED_CAST")
(b as Box<Int>).setX(10)
}
Alex Schiff
04/26/2024, 1:38 PMdmitriy.novozhilov
04/26/2024, 1:39 PMBox<*>
to Box<Int>
to get an ability to write Int
to x
Alex Schiff
04/26/2024, 1:39 PMAlex Schiff
04/26/2024, 1:41 PM(producerFactory as DefaultKafkaProducerFactory<String ,Any>)
worked!Alex Schiff
04/26/2024, 1:41 PMdmitriy.novozhilov
04/26/2024, 1:41 PMAlex Schiff
04/26/2024, 1:41 PM