Kotlin generic type inference limitation

Kotlin generic type inference doesn’t support super constructor call’s argument type.

The IDE says:

Type argument is not within its bounds.

A possible reason is Kotlin doesn’t inference the generic type from its parent.

The issue

Let’s see this example:

interface Cache<T> {
fun setValue(value: T?)
fun getValue(): T?
}

I declare a Cache with setter and getter for any possible type.

interface Blobopen class BlobCache<T : Blob> : Cache<T> {
private var blob: T? = null

override fun setValue(value: T?) {
blob = value
}

override fun getValue(): T? {
return blob
}
}

Then, I declare a data type called Blob and a BlobCache for implementation of Cache which temporarily saves cache in the memory.

To convenient use cache everywhere, I also write a manager like this:

abstract class BlobCacheManager<T : BlobCache<Blob>> {
private var cache: T? = null

fun init() {
cache = createCache()
}

fun save(blob: Blob) {
cache?.setValue(blob)
}

protected abstract fun createCache(): T
}

This BlobCacheManager is a template for operating any cache of Blob. A child class only required to implement the createCache() .

The usage I want is a ImageCache for saving Image in the memory and a ImageCacheManager for using easily. The code looks like below:

class Image(private val expiredAt: Long) : Blob {
fun isExpired(): Boolean {
return System.currentTimeMillis() > expiredAt
}
}

class ImageCache : BlobCache<Image>() {
override fun setValue(value: Image?) {
if (value == null || !value.isExpired()) {
super.setValue(value)
}
}
}
// ImageCache: Type argument is not within its bounds.
class ImageCacheManager : BlobCacheManager<ImageCache>() {
override fun createCache(): ImageCache {
return ImageCache()
}
}

But when I declare ImageCache in the supertype constructor of BlobCacheManager , the IDE says Type argument is not within its bound.

Type argument is not within its bound.
Expected: BlobCache<Blob>
Found: ImageCache

It’s weird. ImageCache is a child of BlobCache<Image> we just declare it.

The cause

The cause is Kotlin inference generic type only by two kinds of type:

  1. Local type inference.
  2. Function signature type inference

You can find out more detail in this document.

Solution

Kotlin doesn’t infer the generic type from a supertype argument. Why don’t we just give it the actual generic type?

abstract class BlobCacheManager<D: Blob, T : BlobCache<D>> {
private var cache: T? = null

fun init() {
cache = createCache()
}

fun save(blob: D) {
cache?.setValue(blob)
}

protected abstract fun createCache(): T
}
class ImageCacheManager : BlobCacheManager<Image, ImageCache>() {
override fun createCache(): ImageCache {
return ImageCache()
}
}

BlobCacheManager requires its child class to pass the exact generic type D and implement ImageCacheManager with an explicit generic type Image .

Finally, the build error has gone, and everything works fine. The solution is simple. We declare two arguments if we can’t do it by one supertype argument.

--

--

--

a developer

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Unity3D: Unable to list target platforms. When I try to build to Android

API for Mobile App Development Explained in Simple Words

Localize your Android App with multiple language options

How to create your social android app with Amity Social Cloud UIKit

Android Localization: An Advanced Guide for Transifex Native

Android 8: Cleartext HTTP traffic not permitted

Android: Hex transparency in colors

Flutter Audiobook Player in 50 lines of code

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Pica

Pica

a developer

More from Medium

Advent of Code 2021 in Kotlin

Android Gradle plugin with Test Fixtures support

Kotlin data class copy and equal behavior need to know.

Gradle Task Ordering