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 xAlex 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