1

I'd like to provide multiple different delegates from a single class, with differing types. For example:

class A {
  val instanceOfB = B()

  val aNumber: SomeType by instanceOfB
  val anotherNumber: SomeOtherType by instanceOfB
}

class B {
  operator fun <T1: SomeType> getValue(thisRef: Any?, property: KProperty<T1>): T1 {
    return SomeType()
  }

  operator fun <T2: SomeOtherType> getValue(thisRef: Any?, property: KProperty<T2>): T2 {
    return SomeOtherType()
  }
}

open class SomeType {}
open class SomeOtherType {}

This example gives the following compiler error: 'operator' modifier is inapplicable on this function: second parameter must be of type KProperty<*> or its supertype

Is there some way to specify the generic type arguments such that I can achieve this?

howettl
  • 12,419
  • 13
  • 56
  • 91

1 Answers1

1

Only way I got it to compile and run, albeit I highly advise against using it aside from proof of concept since inline will generate a lot of trash code, and each getValue call will run through entire when statement:

class B {
  inline operator fun <reified T : Any>getValue(thisRef: Any?, property: KProperty<*>): T {
    return when(T::class.java){
        SomeType::class.java -> SomeType() as T
        SomeOtherType::class.java-> SomeOtherType() as T
        else -> Unit as T
    }
  }
}

There's also operator fun provideDelegate that generates the delegates, but it's limited to 1 return value as well. I don't think there's elegant / supported way to doing what you need right now.

Pawel
  • 15,548
  • 3
  • 36
  • 36
  • Can you qualify what you mean by it will generate a lot of trash code? – howettl Jun 28 '18 at 17:52
  • 1
    @howettl it's an inline function so entire block is copied into calling place. If you check bytecode of your class A, you will find that generated functions `getaNumber()` and `getanotherNumber()` are not calling `instanceOfB` `getValue` method at all. Instead you will see there's entire body of `getValue` copied inside each getter function. – Pawel Jun 28 '18 at 23:10
  • Another thing to watch out for with this approach is if you have multiple delegated properties of the same type, you'll need to ensure you identify them a secondary way (such as with `property.name`) to avoid returning the wrong property. – howettl Jun 29 '18 at 17:18