Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin generics multiple upper bounds (as OR / union construct)

I'm wondering whether it's possible to create a generic class, that accepts an instance of type T, which is limited to (e.g.) an instance of String or an instance of List<String>. See the following pseudo code as an example:

data class Wrapper<T : String | List<String>>(val wrapped: T)

This closely resembles the Union construct, which does not exist in Kotlin (by design). I'm curious whether this can be achieved in a compile time check. The pseudo code class presented above would be used to provide a single object instance of String, and if multiple instances are provided, then it should be a List<String>.

Other options to solve this include:

  1. A separate class for each "variant", i.e.:
    data class Wrapper<T : String>(val wrapped: T)
    data class ListWrapper<T : List<String>>(val wrapped: T)
    
    Downside here obviously is that it's partially duplicated code.
  2. Removing the upper bound, and using an init block to do an instance type check. Downside here is that the check moves to runtime.

Edit: I'm aware of multiple upper bounds using the where keyword, however, that causes a limitation on accepted types which comply to both upper bounds (hence, it's a AND construct)

like image 543
Robin Trietsch Avatar asked Nov 06 '22 03:11

Robin Trietsch


1 Answers

While what you're asking for is impossible in Kotlin currenlty, there might be few alternatives.

One option is to provide two constructors for your data class. The default constructor would take the list of elements, while the secondary one would either take a single/variable element(s):

data class Wrapper<T : String>(val wrapped: List<T>) {
    constructor(vararg wrapped: T) : this(wrapped.toList())
}

Uage:

val list = Wrapper(listOf("a", "b", "c"))
val single = Wrapper("a")
val multiple = Wrapper("a", "b", "c")

One drawback is that your wrapped property will always be a list. Although in some use-cases it might be a good thing.

like image 181
Jakub Zalas Avatar answered Dec 07 '22 16:12

Jakub Zalas