I have the following classes:
sealed class A : BaseType
sealed class B : BaseType
sealed class C : BaseType
...
If I then have a processObject method that looks like this:
fun processObject(obj: BaseType): Int {
return when(obj) {
is A -> 1
is B -> 1
else -> 0
}
}
I notice that I am now repeating myself, so I might change that method to something like this:
fun processObject(obj: BaseType): Int {
return when(obj) {
is A, is B -> 1
else -> 0
}
}
However, this (in my opinion) looks super ugly when the number of classes goes from say 3-4 to 40+. I was thinking of doing something along the lines of the pseudocode below:
// store all the possible types in a list
val typesThatShouldReturn1 = listOf<BaseType>(
// TODO: figure out how to store types in a list without instantiating
)
fun processObject(obj: BaseType): Int {
if (typesThatShouldReturn1.any { obj is it }) {
return 1
}
return 0
}
Is this even possible in kotlin?
Re: some comments.
Why am I not using a marker interface? Because this processEvent function will be implemented in a lot of different contexts and introducing a marker interface for each and every one of them isn't a good solution. Additionally, the baseType classes are part of a CQRS system where ideally our write logic should not be concerned with our read logic. This is the biggest reason why a marker interface isn't viable for me here.
Why doesn't BaseType implement this logic? See comment above about processEvents being implemented in different ways in different contexts. In addition, the base type doesn't have the read logic as a concern so that is why it should never implement this.
Does listOf(A::class, B::class, C::class, ...) look any better than is A, is B, is C, ...? It looks more or less the same.
Valid point. This one is more personal preference as I don't mind a private val typesThatShouldReturn1 nearly as much.
Sure, you can write something like this
val typesThatShouldReturn1 = listOf(
A::class
)
fun processObject(obj: BaseType): Int {
if (typesThatShouldReturn1.any { it.isInstance(obj) }) {
return 1
}
return 0
}
Your example is unclear, but it seems like you were trying to instead do this:
sealed class BaseType
class A : BaseType
class B : BaseType
class C : BaseType
(which means BaseType can only ever be one of A, B, or C — this is consistent with your desired use of when)
What you're effectively saying is that A and B are fundamentally similar and should be handled the same. Assuming A and B actually need to be separate classes, a solution is that they share a common superclass that is not actually BaseType:
sealed class BaseType
open class ABCommon : BaseType
class C : BaseType
class A : ABCommon
class B : ABCommon
fun processObject(obj: BaseType): Int {
return when(obj) {
is ABCommon -> 1
else -> 0
}
}