4ntoine
4ntoine

Reputation: 20418

Does Kotlin `by` keyword work for nullable delegate?

I've pretty excited by Kotlin compiler features and by by in particular - it saves time generating gelegating code:

https://kotlinlang.org/docs/reference/delegation.html

But i want delegate to be nullable and delegating code to check if it's null first and return if it is:

interface Base {
    val message: String
    fun print()
}

class BaseImpl(val x: Int?) : Base {
    override val message = "BaseImpl: x = $x"
    override fun print() { println(message) }
}

class Derived(b: Base?) : Base by b {
    // This property is not accessed from b's implementation of `print`
    override val message = "Message of Derived"
}

fun main() {
    val b = BaseImpl(10)
    val derived = Derived(b)
    derived.print()
    println(derived.message)
}

When compiling ^ i'm getting Type mismatch: inferred type is Base? but Base was expected.

Is it still possible with Kotlin?

To be more detailed i'd like Kotlin compiler to generate forwarding calls to wrapped impl (extWebChromeClient) in https://developer.android.com/reference/android/webkit/WebChromeClient like follows:

private WebChromeClient intWebChromeClient = new WebChromeClient()
  {
    @Override
    public void onReceivedTitle(WebView view, String title)
    {
      if (extWebChromeClient != null)
      {
        extWebChromeClient.onReceivedTitle(view, title);
      }
    }
 ...

Upvotes: 1

Views: 751

Answers (1)

Alexey Romanov
Alexey Romanov

Reputation: 170735

You can make this yourself using dynamic proxies, though I wouldn't really recommend it. Note that for non-void methods there's no way to require overriding them. The below implementation just throws exceptions for them unconditionally, but you could still call them for non-null x.

inline fun <reified T : Any> nullableProxy(x: T?): T {
    val handler = InvocationHandler { _, method, args ->
        if (method.returnType == Void.TYPE) {
            if (x != null) {
                method.invoke(x, *(args ?: arrayOf()))
            }
        } else 
            throw UnsupportedOperationException("Non-void method")
    }

    return Proxy.newProxyInstance(
        T::class.java.classLoader,
        arrayOf(T::class.java),
        handler) as T
}

class Derived(b: Base?) : Base by nullableProxy(b)

This also won't perform as well as implementing methods directly would.

Upvotes: 1

Related Questions