Is there any possiblity to smartcast/return the sa...
# getting-started
h
Is there any possiblity to smartcast/return the same subtype of a sealed class when using it as receiver and when?
Copy code
sealed class F {
  object A: F()
  object B: F()
}
fun F.foo(): F = when (this) {
  is F.A -> F.A
  is F.B -> F.B
}
val a: F.A = F.A.foo() // not possible without a cast
r
Copy code
fun <T : F> T.foo(): T = this
🧌 1
In more seriousness, no, you can't really safely create an instance of a genetic type. If every variant is an
object
, my code will do exactly what you asked. If there are classes, however, you need to tell Kotlin how to create an instance (either via reflection, or by passing another parameter).
h
I didn't mean to create a new instance, I just want to "smartcast" the return value of
foo
to the subclass of the sealed class.
Something like
some F
in Swift
y
Does it have to be an extension function? If not, you can do this:
Copy code
sealed class F<Self : F<Self>> {
  object A: F<A>() {
    override fun foo(): A {
      //do something
      return this
    }
  }
  object B: F<B>() {
    override fun foo(): B {
      //do something
      return this
    }
  }
  abstract fun foo(): Self
}
If it is an extension function, if you're returning the passed-in value every time, then you can do this:
Copy code
fun <T: F> T.foo(): T {
  when (this) {
    is F.A -> // do something for A
    is F.B -> // do something for B
    else -> {} // compiler is stupid, so an else is required
  }
  return this
}
Basically, if you need to create a new instance of T, you'll need some reflection mechanism or some function that's defined to return the Self type, but otherwise, you're safe to do whatever you want and simply return the passed-in value
h
Thanks. Unfortunately, you still need another cast when you use `copy`:
Copy code
sealed class F {
    data class A(val a: Int) : F()
    data class B(val b: Int) : F()
}

fun <T : F> T.foo(): T = when (this) {
    is F.A -> copy(a = a + a)
    is F.B -> copy(b = b + b)
    else -> error("not possible")
} // as T

val a: F.A = F.A(1).foo()
And yes, I need an extension function
y
Yeah in that case it's safe to do the cast inside the
foo
function since you know that it's safe. The issue is that Kotlin doesn't unite the type
T
with F.A when it knows that this is an F.A. There isn't much you can do here sadly unless you can edit the base sealed class and add a copy method to it