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:
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.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)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With