I found some surprising compiler/IDE behavior that...
# compiler
r
I found some surprising compiler/IDE behavior that I’d like to understand. I had this working code:
Copy code
listOfPairs
  .filter { it.first is Banana }
  .map { (banana, foo) ->
    banana as Banana
    eat(banana)
I got a review comment, suggesting this:
Copy code
listOfPairs
  .filterIsInstance<Pair<Banana,Foo>>()
  .map { (banana, foo) ->
    eat(banana)
Looks nice, doesn’t need the
as Banana
part, but it crashes with a class cast exception on the
.map
line, because
Apple can't be cast to Banana
. Why is that and why does it compile? I guess that the “reified” generics from the
.filterIsInstance
inline function only go one level deep, so it checks only for
Pair
, not
Pair<Banana, Foo>
? If that’s the case, it shouldn’t even compile if I specify <Banana, Foo>. Or what is going on here?
e
Copy code
.filterIsInstance<Pair<Banana,Foo>>()
is similar to
Copy code
.filter { it is Pair<Banana,Foo> }
(with an improved return type)
and as generic type arguments are erased at runtime, that does not check anything except
it is Pair<*,*>
1
unfortunately
.filterIsInstance
is unable to show the warning due to other compiler limitations
r
Oh, interesting, your code does indeed give a compile error for
.filter { it is Pair<Banana,Foo> }
Is there an easy to remember rule for which functions don’t give compile errors because of compiler limitations?
e
Hope you got back to the reviewer to update their kotlin knowlege. Its not the most obvious disctinction but its definitely NOT the same behavior before & after.