Search code examples
androidkotlinkotlin-generics

Inferring parameter of class type with default


I have a class with constructor declared like this

class Facade<T : SuperClass>(
    val kClass: KClass<in T> = SuperClass::class
)

It is done like this so that developer doesn't have to specify SuperClass if they want to use it instead of a subclass. Reason to even send the class type is, so that developer doesn't have to specify type in angle brackets .

But now comes the problem. Creating instance like below, says that there is not enough information to infer parameter T. Which is resulting in having to put class into angle brackets.

Facade()

But since default value is SuperClass, then kotlin should be able to infer parameter T as SuperClass. What am I thinking wrong?

Thank you

TL;DR:

Facade(SubClass:class) // working
Facade(SuperClass:class) // working, but don't want (superclass is default)
Facade<SuperClass>() // working, but don't want angle brackets <>
Facade() // not working, cannot infer T type from default, why?

Solution

  • For the Facade() to be equivalent to Facade(DerivedClass::class) the default constructor parameter would have to be declared as val kClass: KClass<in T> = T::class. However to use T::class the T type parameter would need to be reified. A type parameter can only be reified in inline functions and not constructors.

    To workaround this issue you can declare a factory function that delegates to constructor like so:

    inline fun <reified T : SuperClass> Facade(): Facade<T> = Facade(T::class)
    

    This allows one to use it as e.g.:

    val derivedFacade:Facade<DerivedClass> = Facade()
    

    Note that if you would like to use the SuperClass as the default parameter for T you would need to declare another factory method using different name e.g.:

    fun SuperFacade(): Facade<SuperClass> = Facade()
    

    This is required since if we had declared @JvmName("SuperFacade") fun Facade() = Facade(SuperClass::class) the compile would match it whenever we do not provide type parameters. This in turn would defy the type inference from the derivedFacade example.