3

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?
Majkeee
  • 960
  • 1
  • 8
  • 28

2 Answers2

0

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.

miensol
  • 39,733
  • 7
  • 116
  • 112
0

You can resolve your problem by removing the angle brackets and changing the constructor type. Just use this constructor:

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

All these call are working

Facade(SubClass:class)
Facade(SuperClass:class)
Facade()
Maurice
  • 2,129
  • 2
  • 25
  • 33
  • Oh, nice catch. My mistake I didn't specify it, but I actually do need the T for property and in methods. Also, I am not able to make upper bound of SuperClass (only superclass and its derivates can go to this constructor). – Majkeee Feb 06 '18 at 13:57