arekolek
08/02/2019, 11:41 AMsealed class Item {
data class Foo(val id: Int) : Item()
object Bar : Item()
}
fun List<Item>.trim() = dropLastWhile { it is Item.Bar || it.id == IGNORED_ID }
It works if I do it !is Item.Foo || it.id == IGNORED_ID though, which is understandablediesieben07
08/02/2019, 11:43 AMarekolek
08/02/2019, 11:43 AMdiesieben07
08/02/2019, 11:44 AMmarstran
08/02/2019, 11:53 AMit !is Item.Foo is false, then it must be Item.Foo. Even if you would later add another subclass to Item.
If it is Item.Bar is false however, then it can be any other subclass of Item. The smart cast would break if you added a new subclass to Item.marstran
08/02/2019, 11:53 AMdiesieben07
08/02/2019, 11:55 AMdiesieben07
08/02/2019, 11:55 AMItem.Foo is the only type mentioned in your type check, so it's the only type that can be smart-casted towbertan
08/02/2019, 12:34 PMit !is Item.Foo || it.id == 999
if (it instanceof PathTest.Item.Foo && ((PathTest.Item.Foo)it).getId() != 999) { ... }
In my guess, the way it "optimizes" it, allows the smart cast to be in place and do the second check.
While the it is Item.Bar || it.id == IGNORED_ID will probably "optimize" in a way it cannot "smart" cast to the second expression as it probably didn't rule out the type.
Tweaking a little your example to:
sealed class Item(val name: String) {
data class Foo(val id: Int) : Item("foo")
object Bar : Item("bar")
}
and making it is Item.Bar || it.name == "other" it will compile and generate:
if (!(it instanceof PathTest.Item.Bar) && !Intrinsics.areEqual(it.getName(), "other")) {...}
So we can see how it "optimizes" the first expression, while the one where it "works" it checks if it is an instaceof Item.Foo, this being true will check the second expression knowing the instance is a Foo. In this second example it simply check if isn't Bar, and when reaching the second expression what it knows is the class isn't a Bar but could be anything else (not exactly a Foo).