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

Exploring Android 13: Photo Picker

Android App Fundamentals

Copyright Profiles Android Studio

Jetpack Compose Interop Part 1: Using Traditional Views and Layouts in Compose with AndroidView

Modularization of Android Applications in 2021

API for Mobile App Development Explained in Simple Words

Android: Hex transparency in colors

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

Non-fatal crashes: the crash rate that matters

MVP/MVC to Reactive Architectures for Jetpack Compose

Android MVC structure from https://www.codementor.io/@dragneelfps/implementing-mvc-pattern-in-android-with-kotlin-i9hi2r06c

Variable names in Kotlin when expressions

The magic of RxJava with a bit of Kotlin awesome collections tools