Java & Kotlin casting with generics. Losing typesafety -
when coding in kotlin/java, stumbled onto rather odd while using casting , generics. seems possible have type system believe list of type list<foo>
, while list<object>
.
can explain me why possible?
here example in both kotlin , java of issue:
example in kotlin
fun <t> test(obj: any): list<t> { val ts = arraylist<t>() ts.add(obj t) return ts } fun <t> test2(obj: any): t { return obj t } fun <t> test3(obj: any): list<t> { val ts = arraylist<t>() ts.add(test2(obj)) return ts } fun main(args: array<string>) { val x = test<double>(1) // returns list of integers , doesn't error println(x) val y = test2<double>(1) // casts int object double. println(y) val z = test3<double>(1) // returns list of integers , doesn't error. println(z) }
example in java
public class test { public static <t> list<t> test(object obj){ arraylist<t> ts = new arraylist<>(); ts.add((t) obj); return ts; } public static <t> t test2(object obj){ return (t) obj; } public static <t> list<t> test3(object obj){ arraylist<t> ts = new arraylist<>(); ts.add(test2(obj)); return ts; } public static void main(string[] args) { list<double> x = test(1); // returns list of integers , doesn't error system.out.println(x); // double y = test2(1); // errors in java integers cannot converted double. // system.out.println(y); list<double> z = test3(1); // returns list of integers , doesn't error. system.out.println(z); } }
java doesn't have reified generics. is, generic information not exist @ runtime, , generic code "simplified" process called erasure. compiler throws in casts when generic types known ensure correctness. can't cast generic type, then, generic types don't exist enough runtime know whether value 1 or not, , why javac
yells @ doing this, because knows asking jvm cannot possibly do, introducing runtime unsafety.
public class test { public static list test(object obj) { // generic types => erasure = raw types arraylist ts = new arraylist(); ts.add(obj); // no cast: list.add has erasure (ljava.lang.object;)v return ts; } public static object test2(object obj) { // t unbounded => erasure = object return obj; // no cast: types <: object } public static list test3(object obj) { arraylist ts = new arraylist(); ts.add(test2(obj)); // note: don't know t is, can't cast , ensure test2 returned one. return ts; } public static void main(string[] args) { list x = test(1); // returns list , doesn't error system.out.println(x); double y = (double) test2(1); // errors in java integer cannot converted double // because compiler needs insert casts make generics work system.out.println(y); list z = test3(1); // unlike y, there isn't cast in test3 because test3 doesn't know t is, integer passes through, uncast, list<double>. // jvm can't detect this, because doesn't know list<double> is. system.out.println(z); } }
note how test2
erases glorified identity function, causing test3
same thing test1
, level of indirection.
Comments
Post a Comment