[)roi(]
Executive Member
- Joined
- Apr 15, 2005
- Messages
- 6,282
A new research paper points to problems in Java and Scala generics since its introduction in Java 5 i.e. 12 years ago. Not surprising generics are notoriously difficult to get right, even with 12 years of extensive use; inherent design flaws are often overlooked.
Which has "sorted of" been patched with recent updates. i.e. "return bind.upcast(constrain, t);" reports an error with Java 1.8.0_112
However this version 9 compatible example still permits "type safe" casting of an Integer to a String.
Here's a playground with runnable versions of the various code examples.
The report on this is very detailed and an interesting read, however for the TLDR; here's their conclusion:
PHP:
/**
* javac, version 1.8.0_25
*/
class Unsound {
static class Constrain<A, B extends A> {}
static class Bind<A> {
<B extends A> A upcast(Constrain<A, B> constrain, B b) {
return b;
}
}
static <T,U> U coerce(T t) {
Constrain<U, ? super T> constrain = null;
Bind<U> bind = new Bind<U>();
return bind.upcast(constrain, t);
}
public static void main(String[] args) {
String zero = Unsound.<Integer, String>coerce(0);
}
}
However this version 9 compatible example still permits "type safe" casting of an Integer to a String.
PHP:
class Unsound9 {
static class Type<A> {
class Constraint<B extends A> extends Type<B> {}
<B> Constraint<? super B> bad() { return null; }
<B> A coerce(B b) {
return pair(this.<B>bad(), b).value;
}
}
static class Sum<T> {
Type<T> type;
T value;
Sum(Type<T> t, T v) { type = t; value = v; }
}
static <T> Sum<T> pair(Type<T> type, T value) {
return new Sum<T>(type, value);
}
static <T,U> U coerce(T t) {
Type<U> type = new Type<U>();
return type.<T>coerce(t);
}
public static void main(String[] args) {
String zero = Unsound9.<Integer,String>coerce(0);
}
}
Here's a playground with runnable versions of the various code examples.
The report on this is very detailed and an interesting read, however for the TLDR; here's their conclusion:
It's the wildcard's fault: "<? super B>" i.e. the encoding of variances with genericsWe have shown that Java and Scala are unsound and have been for 12 years. Their unsoundness is due to an unforeseen interaction of features that are each sound separately. The unsoundness was missed repeatedly due to our community’s reliance upon minimal calculi; mechanically verified proofs would not have prevented the problem. Any language with types that provide evidence without directly using the corresponding value is susceptible to this issue. Given that this issue was missed even after significant formalization effort, it is likely that many less-thoroughly-examined hypothetical languages and features in our literature share the same problem. This suggests that we as a community need to encourage more research on holistic language design and formalization so that we can prevent such problems in the future.