Summary
Based on the experiences with the previous round of preview, we propose the following update:
- make
instanceof
aware of the deduced type of the relational expression when the type on RHS is a primitive type.
Problem
Currently, and after the first preview, the following two examples work as expected (relevant discussion).
Short s = 42;
s instanceof int
// correctly evaluates to true, because s has static type Short
// the conversion that is safeguarded is the following: Short -> short -> int
Object o = s;
o instanceof int
// correctly evaluates to false, because o has static type Object
// the conversion that is safeguarded is the following: Object -> Integer -> int (s is of type Short so this fails)
However, javac accepts the following two with different runtime behavior:
List<Short> ls = List.of((short) 42);
switch(ls.get(0)) {
case int _ -> true;
default -> false;
}
// correctly evaluates to true,
// since an automatically generated cast is inserted with the deduced type ((Short) ls.get(0)).
ls.get(0) instanceof int
// erroneously evaluates to false, since what is executed is ls.get(0): Object instanceof int.
// instanceof should safeguard the Short -> short -> int conversion
// instead, instanceof safeguards the Object -> Integer -> int conversion (and fails).
There are two requirements here. instanceof
should continue being the
precondition of safe casting and safe casting is described in Section 5.5. The
second is that switch
and instanceof
should expose the same behavior.
While the automatically generated cast ensures safety in terms of heap pollution in the selector expression of switch by raising a CCE, instanceof never intended to raise a CCE in case of heap pollution for the evaluation of its relational expression.
Solution
There are two alternatives:
Sharp Cast Insertion: Automatically insert a sharp cast with the deduced type to the relational expression similarly to switch.
e.g.,
(Short) ls.get(0) instanceof int
This approach would align the behavior of the new
instanceof
withswitch
.In that case, an automatically generated cast would ensure that heap pollution is signaled similarly with
switch
. However,instanceof
will start raising a CCE in case of heap pollution (somethinginstanceof
has traditionally avoided).Pattern-based Translation: Instead of introducing a sharp cast, use a pattern that first checks for the deduced type and then performs the instanceof test with the original RHS of the instanceof.
e.g.,
ls.get(0) instanceof Short s && s instanceof int
That retains the unwritten philosophy of
instanceof
that never throws--even in the case of heap pollution--at the expense of a more complex translation.
In the second preview we address this issue by following the second (2) option.
This maintains the philosophy of instanceof
not throwing exceptions, even in
cases of heap pollution, while ensuring the correct behavior when testing
primitive types.
Specification
The JLS draft showing the exact wording for the above solutions is attached as JLS-instanceof-1.pdf
- csr of
-
JDK-8341408 Implement JEP 488: Primitive Types in Patterns, instanceof, and switch (Second Preview)
-
- Resolved
-