Kotlin: Function that returns a generic type. What If I do not know which concrete type should get returned?

kotlin generic function
kotlin generic function example
kotlin generic extension function
kotlin pass class type as parameter
kotlin reified
kotlin generic t extends class
kotlin create instance of generic type
kotlin class type

I have the following type:

class Images<T : Image>(
    val images: List<T>,
    val totalCount: Int
)

So the list here can only contain objects which are inheriting from Image.

Now I have an interface:

interface ImageService<T : Image> {
    fun getNewImages(offset: Int, limit: Int): Images<T>

    fun getNextImage(): Image
}

And a concrete implementation:

class NumberImageService : ImageService<NumberImage> {
    override fun getNewImages(offset: Int, limit: Int): Images<NumberImage> {
        // return something
    }

    override fun getNextImage(): NumberImage {
        // return something
    }
}

So far, so good. Now I have another class where I decide which concrete implementation to use based on an enum input:

class ImageQueryResolver : GraphQLQueryResolver {
    fun getNewImages(input: ImageInput, offset: Int, limit: Int = Int.MAX_VALUE): Images {
        return when (input.imageType) {
            ImageEnum.NUMBER ->
                numberImageService.getNewImages(offset, limit)
            ImageEnum.LETTER ->
                letterImageService.getNewImages(offset, limit)
        }
    }

    fun getNextImage(input: ImageInput): Image {
        // return something
    }
}

So this is giving me an error because the return type of getNewImages, which is Images needs to have an argument:

One type argument expected for class Images<T : Image>

But which argument do I need to use now?

As I mentioned in a comment, you can use Images<out Image> as the return type. This is basically saying the implementation may use Image or a subtype of Image. If you're familiar with Java then it's similar to using Images<? extends Image>.

Since your Images interface only ever produces objects of type T another option is to use declaration-site variance instead of use-site variance. In other words, you could have:

interface Images<out T : Image> {
    // methods...
}

Which will let you use Images<Image> as the return type:

fun getNewImages(input: ImageInput, offset: Int, limit: Int = Int.MAX_VALUE): Images<Image> {
    return when (input.imageType) {
        ImageEnum.NUMBER ->
            numberImageService.getNewImages(offset, limit)
        ImageEnum.LETTER ->
            letterImageService.getNewImages(offset, limit)
    }
}

Here's the reference on generics in Kotlin: https://kotlinlang.org/docs/reference/generics.html

Generics: in, out, where, First, generic types in Java are invariant, meaning that List<String> is not a subtype of List<Object> . If List was not invariant, it would have been no better than Java's arrays, since do not know what objects comply to that unknown subtype of E . In return for Type parameters are placed before the name of the function:. The only advantage of having Generics here is the checking of the proper return type if the class is defined properly. – tynn Jun 16 '18 at 0:40 Not true. The return type of cloneMe() is Content , regardless of the fact that you call it from a Music and it returns a Music instance.

You need to specify that argument, because Images is generic. So, I would suggest one of two:

1) Images<out Image> -> return type is a subtype of Image

2) Images<*> -> I dont care what generic type is there

I think first solution is better (we bounded that value, so we know more what's going all) ;)

Generic type parameters - Generics, It is also possible to make functions that take more generic parameters than the If you want to impose additional constraints, you must use a separate where clause, If you have an instance of Generic<Subtype> , and you want to refer to it as a If you do, you may only use that type parameter as a return type, not as a​  The contravariant type parameter of a parameter of a function-typed return type (the user will call the returned function with something that can consume any Fruit, so it's okay to return a function that expects to receive something that can handle Apple) A contravariant type parameter may be used in the converse situations.

Try this:

fun <T : Image> getNewImages(input: ImageInput, offset: Int, limit: Int = Int.MAX_VALUE): Images<T> {
  return when (input.imageType) {
    ImageEnum.NUMBER ->
      numberImageService.getNewImages(offset, limit)
    ImageEnum.LETTER ->
      letterImageService.getNewImages(offset, limit)
  }
}

Type Checks and Casts: 'is' and 'as', We can check whether an object conforms to a given type at runtime by using the is smart enough to know a cast to be safe if a negative check leads to a return: Note that null cannot be cast to String as this type is not nullable, i.e. if y is null, Inline functions with reified type parameters have their actual type arguments  Similarly, you can define in types for generic types that are only ever passed into methods, not returned. This allows Kotlin to do extra checks for code safety. This allows Kotlin to do extra

Kotlin for Android App Development, A common example is to check whether an object is a subtype of the type parameter. However, type information for generic type parameters is not preserved at Listing 4.52 illustrates an example with a generic function that filters an iterable object by a given type. Must suppress unchecked cast return this.filter { clazz. Type parameter T is declared as 'out' but occurs in 'in' position in type T. And now we know why Kotlin won’t let us put a type parameter in a function parameter position when it’s marked as out - it’s not type-safe because it violates Rule #1! Creating Contravariance. Let’s change the scenario.

Self Types - Language Design, In a 2012 roadmap I saw a reference to supporting "Self types" I see that the Swift, unlike Kotlin, does not have to interoperate with the JVM. @yole Is it not possible to implement it as recursive generic Foo<Self: Foo<Self>> under the hood? Methods returning a This type in interfaces or open classes must return itself  Generic type parameters are erased at runtime, read about type erasure if you haven't already. Reified type parameters on inline functions not only inline the method body, but also the generic type parameter allowing you do to things like T::class.java (which you can't do with normal generic types). Putting as a comment because I don't have

Kotlin - Generics, How do you pass a function as a parameter in Kotlin? Using the power of generic types combined with extension functions, we can do very interesting things. I encourage you to create your own functions that allow you to make your daily work easier. And if you want to learn how to use Kotlin to develop your own Android Apps, I recommend you take a look at my free training.

Comments
  • You can have ImageQueryResolver#getNewImages return Images<out Image>.
  • This works. Thank you! I will read why it works though ^^
  • This reference may help: kotlinlang.org/docs/reference/generics.html. If you're familiar with Java it's similar to using Images<? extends Image>.
  • Thank you very much
  • Hi. Thx for your reply. That does not work. It leads to a type missmatch between Images<T> and Images<NumberImage>. However, putting in Images<out T> as return type for that function works.