Is there a way to accept an argument that is either of type A or B in Kotlin?

Viewed 604

Assuming I have A and B:

data class A(val a: String, val common: String)
data class B(val b: String, val common: String)

Can I have a method that accepts either one and use common in it? something like:

fun accept(val param: A|B) {
    println(param.common)
}
3 Answers

Sealed classes do pretty much that:

sealed class AorB (val common : String)
class A(val a: String, common: String) : AorB(common)
class B(val b: String, common: String) : AorB(common)

fun accept(param: AorB) {
    println(param.common)
    when(param) {
        is A -> println(param.a)
        is B -> println(param.b)
    }
}

fun main() {
    accept(A("a value", "common value")) 
    accept(B("b value", "common value")) 
}

You can do it if you have them both implement a common interface, and use the interface as the type of parameter:

interface HasCommon {
    val common: String
}

data class A(val a: String, override val common: String) : HasCommon
data class B(val b: String, override val common: String) : HasCommon

fun accept(param: HasCommon) {
    println(param.common)
}

fun main() {
    accept(A("a", "a"))
    accept(B("b", "b"))
}

Output:

a
b

Alternatively, you could do it in a more functional way by defining multiple versions of accept for each type, and abstracting out the common functionality:

data class A(val a: String, val common: String)
data class B(val b: String, val common: String)

fun accept(a: A) = printCommon(a.common)
fun accept(b: B) = printCommon(b.common)

fun printCommon(common: String) = println(common)

fun main() {
    accept(A("a", "a"))
    accept(B("b", "b"))
}

Inheritance is supposed to fix this problem

After all, accepting either would mean you can't call any specific methods on them unless you cast them.

That would be the same thing as accepting "Any" in Kotlin.

A workaround would be to define 2 methods where one method could call the other one after casting it.

Or you make the classes inherit but you are using data classes so I assume you already know that that isn't easily possible with them.

A workaround for inheritance with data classes is this

Related