How can I use multiple type generics in kotlin?

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 ){
    ...
}
1 Like

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?

3 Likes

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

1 Like

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.

1 Like

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.

2 Likes

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

1 Like