Kotlin does not support multi-typing. However, you can apply workarounds.
First, to help modeling your problem, you could create a super type (interface or abstract class) as suggested in comments, to extract common properties, or just have a "marker" interface. It allows to narrow accepted objects to a certain category, and improve control.
Anyhow, you can filter any list to get back only values of wanted type using filterIsInstance
:
enum class InstrumentFamily {
Strings, Keyboards, Winds, Percussions
}
abstract class Instrument(val family : InstrumentFamily)
data class Guitar(val stringCount : Int) : Instrument(InstrumentFamily.Strings)
data class Piano(val year: Int) : Instrument(InstrumentFamily.Keyboards)
fun main() {
val mix = listOf(Guitar(6), Piano(1960), null, Guitar(7), Piano(2010))
val guitars: List<Guitar> = mix.filterIsInstance<Guitar>()
guitars.forEach { println(it) }
val pianos : List<Piano> = mix.filterIsInstance<Piano>()
pianos.forEach { println(it) }
}
However, beware that this operator will scan all list, so it can become slow if used with large lists or many times. So, don't rely on it too much.
Another workaround would be to create an index per type, and use sealed classes to ensure full control over possible types (but therefore, you'll lose extensibility capabilities).
Exemple :
import kotlin.reflect.KClass
enum class InstrumentFamily {
Strings, Keyboards, Winds, Percussions
}
sealed class Instrument(val family : InstrumentFamily)
data class Guitar(val stringCount : Int) : Instrument(InstrumentFamily.Strings)
data class Piano(val year: Int) : Instrument(InstrumentFamily.Keyboards)
/** Custom mapping by value type */
class InstrumentContainer(private val valuesByType : MutableMap<KClass<out Instrument>, List<Instrument>> = mutableMapOf()) : Map<KClass<out Instrument>, List<Instrument>> by valuesByType {
/** When receiving an instrument, store it in a sublist specialized for its type */
fun add(instrument: Instrument) {
valuesByType.merge(instrument::class, listOf(instrument)) { l1, l2 -> l1 + l2}
}
/** Retrieve all objects stored for a given subtype */
inline fun <reified I :Instrument> get() = get(I::class) as List<out I>
}
fun main() {
val mix = listOf(Guitar(6), Piano(1960), null, Guitar(7), Piano(2010))
val container = InstrumentContainer()
mix.forEach { if (it != null) container.add(it) }
container.get<Guitar>().forEach { println(it) }
}