pniederw
12/10/2019, 8:18 PMwhen
had better smart casts. I'm often hitting this case:
open class Animal
class Cat : Animal()
class Dog : Animal()
when (any) {
is Cat, is Dog -> // I wish `any` had type `Animal` here, not `Any`
}
LeoColman
12/10/2019, 8:20 PMpniederw
12/10/2019, 8:22 PMAnders Mikkelsen
12/10/2019, 9:35 PMcodeslubber
12/10/2019, 10:04 PMAnders Mikkelsen
12/10/2019, 10:11 PMpniederw
12/10/2019, 10:14 PMAnimal
in the is Cat, is Dog
branch of the when
expression. other branches aren't shown here.pniederw
12/10/2019, 10:15 PMcodeslubber
12/10/2019, 10:20 PMpniederw
12/10/2019, 10:21 PMlistOf(Cat(), Dog())
has inferred type List<Animal>
today.pniederw
12/10/2019, 10:21 PMcodeslubber
12/10/2019, 10:24 PManimal
would make sensepniederw
12/10/2019, 10:26 PMAnimal
will always succeed.Anders Mikkelsen
12/10/2019, 11:01 PMAnders Mikkelsen
12/10/2019, 11:06 PMAnders Mikkelsen
12/10/2019, 11:07 PMcodeslubber
12/10/2019, 11:10 PMBarco
12/11/2019, 12:57 AMBarco
12/11/2019, 12:58 AMsealed class Animal {
object Dog : Animal()
object Cat : Animal()
}
val animal: Animal = Animal.Dog
when (animal) {
is Animal.Dog -> animal
else -> animal //This could be inferred to be a Cat, but instead stays as an Animal.
}
Barco
12/11/2019, 1:00 AMTim McCormack
12/11/2019, 1:27 AMpniederw
12/11/2019, 3:01 AMlistOf(Cat(), Dog())
has inferred type List<Animal>
. same thing really.pniederw
12/11/2019, 3:04 AMlistOf
example).pniederw
12/11/2019, 3:06 AMopen
.Barco
12/11/2019, 3:54 AMsealed class Animal {
object Dog : Animal()
object Cat : Animal()
}
class DogContainer<T> : Container<T>
interface Container<T> {
companion object {
fun <T> just(element: T): Container<T> = DogContainer()
}
}
val animal: Animal = Animal.Dog
fun getAnimal(): Container<Animal> {
val newAnimal = when (animal) {
is <http://Animal.Cat|Animal.Cat> -> Animal.Dog
else -> animal //Inferring this to be a Dog would cause a compiler error..
}
val container = Container.just(newAnimal) //..as this container's parameter becomes Animal.Dog
//Do some other stuff with the container..
return container
}
pniederw
12/11/2019, 4:32 AMelse
branch.Barco
12/11/2019, 4:34 AMwhen
statements in general. Perhaps I have misunderstood.pniederw
12/11/2019, 4:36 AMpniederw
12/11/2019, 4:37 AMis Dog, is Cat ->
as for listOf(Dog(), Cat())
.pniederw
12/11/2019, 4:37 AMAnders Mikkelsen
12/11/2019, 7:10 AMpniederw
12/11/2019, 9:32 AMlistOf(Cat(), Dog())
does today. I've also answered the other question before.Anders Mikkelsen
12/11/2019, 9:46 AMopen class Animal
class Cat : Animal(), MouthBreather
class Dog : Animal(), MouthBreather
class Fish : Animal()
interface MouthBreather
fun main() {
val someList = listOf(Cat(), Dog())
val secondList = listOf(Fish())
val list: List<Animal> = listOf(Cat(), Dog())
val listTwo: List<MouthBreather> = listOf(Cat(), Dog())
}
In this case someList is of subtype Any, and secondlist is of subtype Fish. ie. is Cat, is Dog would still infer Any in this case, not animal. is Fish would tho, making the entire when pretty unpredictable unless you know the entire hierarchy.pniederw
12/11/2019, 9:59 AMAnders Mikkelsen
12/11/2019, 10:03 AMpniederw
12/11/2019, 10:05 AMpniederw
12/11/2019, 10:12 AMwhen
already behaves the same as listOf()
, and as you stated, the whole thing breaks down when the classes have interfaces in common. 😞Anders Mikkelsen
12/11/2019, 10:13 AMpniederw
12/11/2019, 10:16 AMAnimal & MouthBreather
, but Kotlin's type system can't express that.pniederw
12/11/2019, 10:17 AMdmitriy.novozhilov
12/24/2019, 8:54 AMis
in when
condition is known problem of current data flow analys
it can intersect smartcast infos from cond1 && cond2
, but can't union them from cond1 || cond2
this problem will be fixed in new compiler that was announced on kotlinconfdmitriy.novozhilov
12/24/2019, 8:56 AMthe type should really beactually, with enabled new inference algorithm you can use implicit intersection types This is valid code with new inference:, but Kotlin's type system can't express that.Animal & MouthBreather
interface A {
fun foo()
}
interface B {
fun bar()
}
interface C : A, B
interface D : A, B
fun <K> select(x: K, y: K): K = x
fun test(c: C, d: D) {
val x = select(c, d) // x: {A & B}
x.foo()
x.bar()
}
but there is limitation that intersection types can not be writen explicitly, so they can appear only in local declarations