How can I use multiple type generics in kotlin? In my real development, I think this feature is very useful and I really need this feature
like this:
class Animal{}
class Fruit{}
fun < T : Animal or Fruit> have( someThing : T ){
...
}
How can I use multiple type generics in kotlin? In my real development, I think this feature is very useful and I really need this feature
like this:
class Animal{}
class Fruit{}
fun < T : Animal or Fruit> have( someThing : T ){
...
}
That’s not possible.
Also if the types are unrelated I can’t imagine you writing code which is any different than “if T is Animal …”
Could you share a real example of where you needed this?
Instead make sure that class Animal
and class Fruit
shares a common interface.
I need to limit the type of input at the syntax level when calling, so that I can clearly know the type passed in,Animal or Fruit, instead of using an ambiguous Any
I understand what you mean, it is indeed possible to use an interface to fulfill this requirement, but sometimes, the incoming is not the same type, such as when I am sorting a list.
The list contains many different types of objects, and I need to use different sorting rules according to different types of objects.
I need to explicitly limit the types that are allowed to be passed in when the function passes in parameters, instead of writing an ambiguous type of Any instead
As far as I know, Microsoft’s typescript has done this language feature
Function overloading maybe, implement two functions with the same name but different types.
It does, but…it’s not what I want.
The simple answer is: no, this is not possible in Kotlin. People just give you alternatives.
What you mean here is a union type. You can also look at sealed interfaces/classes, however, this is also not exactly the thing you ask.
Have they?
They mostly were forced by the fact that JS had functions whose behaviour changed depending on the type of the argument, so they didn’t have a real choice.
The or-types VS inheritance appraoch has been discussed in other threads, fundamentally they’re 2 different takes on polymorphism, and for time being, Kotlin is in the field of inheritance.
Depending on your use case there’s probably a good solution where or-types are not required.
What you’re describing is called a “sum type”, or sometimes “tagged union”. As mentioned by others, Kotlin’s type system does not directly support this, except in the limited case of sub-typing (extending a common class, or implementing a common interface). Technically, nullable types are also a sort of very restricted sum type.
For just a function parameter, most of the time it’s probably better to just overload the function.
However, if you want to be able to hold onto the “Animal or Fruit”, return it as a result, or just accept either type without statically knowing which you’re going to get, that won’t work.
One way you can possibly accomplish what you’re trying to do is to have a container that manages the sum type for you. This would normally be done with a sealed class, with one subclass for each of the types you wanted to “combine”. If you have exactly two types you need to combine, you can use the generic Either from arrow-kt rather than writing a custom sealed class. (The docs for Either focus on the common case of using it for “an error value or a success value”, but it doesn’t have to be used that way.)
For example:
fun have(someThing: Either<Animal, Fruit>){
...
}
fun give(): Either<Animal, Fruit>{
...
}
I would certainly love this feature… I very much need this in my project too
Yes you can achieve multiple upperbounds using the where-clause, although there are some limitations; only one class is allowed, and the class must be open
.
You can read more about upper bounds in the kotlin documentation on generics Generics: in, out, where | Kotlin Documentation
open class Animal {
val alive = true
}
interface Fruit {
fun taste(): String
}
fun <T> have(something: T): Boolean where T : Animal, T : Fruit {
return something.alive && something.taste() == "weird"
}
// Usage
private val horse = object : Animal(), Fruit {
override fun taste(): String = "rasins"
}
have(horse)
I would only recommend using it when absolutely necessary, there are better solutions for most use-cases.
It’s not a very well known feature but it has been in the language since at least 2019.
Here, where T : Animal, T : Fruit
mean “And” (T is Animal and Fruit)
Union type (or either) means “Or”;
Animal|Fruit
mean it’s an animal or a fruit;
Animal?
is a kind of union type, animal or null.
The case where union type would be more useful is may be for collections; as Properties in Java is a map of Object.
it could be defined as :
typealias Value = Int|String|LocalDate
class Properties<T> {
val properties = HashMap<String, T|Properties>()
fun get(key: String) : T|Properties|Null { return this.properties[key] }
}
val props = Properties<Value>()
So, a property is either a value (String, Int, Date in this case), or a sub propertie set