pdegand
05/13/2019, 4:05 PMsealed class Bird
class Chicken: Bird()
class Turkey: Bird()
class Egg<T: Bird>
I want to implement a function fun <T: Bird> T.layEgg(): Egg<T>
.
The only way I found to implement it with the compiler being ok with is like that :
fun <T: Bird> T.layEgg(): Egg<T> {
return when(this as Bird) {
is Chicken -> Egg<Chicken>()
is Turkey -> Egg<Turkey>()
} as Egg<T>
}
fun main() {
val egg: Egg<Chicken> = Chicken().layEgg()
}
But IDEA tells me that the first as Bird
in the when is useless, but if I remove it, the compiler complains that the when is not exhaustive.
And the final as Egg<T>
is marked as unsafe but I need it because returning an Egg<Chicken> is not and Egg<T>.
Is there a way to have this implemented a better wat or is this simply impossible with generics ?
ThanksShawn
05/13/2019, 4:10 PMfun <T : Bird> Bird.layEgg(): Egg<out T> {
return when(this) {
is Chicken -> Egg<Chicken>()
is Turkey -> Egg<Turkey>()
}
}
fun main() {
val egg: Egg<Chicken> = Chicken().layEgg()
}
edit: turns out this doesn’t actually compile, playground lied to me 👺Shawn
05/13/2019, 4:13 PMpdegand
05/13/2019, 4:30 PMsealed class Bird {
abstract fun <T: Bird> layEgg(): Egg<T>
}
But with this, every subclass has the same implementation of the layEgg method and when calling layEgg()
on a subclass, I have to specify the type of Bird
class Chicken: Bird() {
override fun <T : Bird> layEgg(): Egg<T> = Egg()
}
class Turkey: Bird() {
override fun <T : Bird> layEgg(): Egg<T> = Egg()
}
class Egg<out T: Bird>
fun main() {
val egg = Chicken().layEgg<Chicken>()
}
Bob Glamm
05/13/2019, 6:28 PMBob Glamm
05/13/2019, 6:28 PMsealed class Bird
data class Chicken(val x: String): Bird()
data class Turkey(val y: String): Bird()
class Egg<T: Bird>
fun <T: Bird> T.layEgg(): Egg<T> = Egg()
fun main(args: Array<String>): Unit {
val egg = Chicken("x").layEgg()
println(egg)
}
Bob Glamm
05/13/2019, 6:28 PMegg
is of type Egg<Chicken>
in main()
Bob Glamm
05/13/2019, 6:29 PMEgg
requires a different constructor then you're back to when
and an apparent failure at exhaustiveness checkingBob Glamm
05/14/2019, 1:43 PMEgg<T>
but IJ correctly determines the when
is exhaustive:
sealed class Bird
data class Chicken(val x: String): Bird()
data class Turkey(val y: Double): Bird()
class Egg<T: Bird>
fun layEggImpl(bird: Bird): Egg<*> = when(bird) {
is Chicken -> Egg<Chicken>()
is Turkey -> Egg<Turkey>()
}
fun <T: Bird> T.layEgg() = layEggImpl(this) as Egg<T>
fun main(args: Array<String>): Unit {
val egg= Chicken("foo").layEgg()
println(egg)
}
Bob Glamm
05/14/2019, 1:44 PMegg
in main
is correctly inferred to be Egg<Chicken>