Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a simple null safe operator for Kotlin function references?

Tags:

kotlin

I'd like to pass a function reference on a nullable object. To take an Android example, say I want to use Activity#onBackPressed from a fragment that is a child of that actvity.

If I wanted to invoke this function, I could easily do

activity?.onBackPressed()

However, say I wanted to pass that as a reference instead:

val onBackPressedRef = activity::onBackPressed

This gives the familiar null safe error of Only safe or non null assserted calls are allowed...


I can get the error to go away with the following, but using !! is obviously not ideal:

val onBackPressedRef = activity!!::onBackPressed

Attemping activity?::onBackPressed was my first instinct, but this also breaks with several errors, where the interpreter seems confused.

val onBackPressedRef = activity?.let { it::onBackPressed } 

This last variation works, but it's a lot more ugly than just using ?::. I checked all the docs I could find, but I feel like I'm missing something. Any ideas?

like image 269
lase Avatar asked Nov 11 '19 21:11

lase


1 Answers

You are right, there is no ?:: operator in Kotlin.
You have several alternatives:

1. let and run

Thus, you have to use a helper function. Instead of let(), you can also use run(), making the expression a tiny bit shorter:

val onBackPressedRef = activity?.let { it::onBackPressed }
val onBackPressedRef = activity?.run { ::onBackPressed }

But keep in mind that either way, the invocation will be more verbose, too:

onBackPressedRef?.invoke(args)

Thus you should ask yourself, if this is really what you want, or if a no-op function call is also acceptable.

2. Closures

You could use a closure -- this will change semantics however:

val onBackPressedRef = { activity?.onBackPressed() }

Here, onBackPressedRef is not nullable anymore, so you can call it using the () operator, and in case of null activity it will have no effect.

3. Helper function

If function references with nullable objects are something you encounter a lot, you can write your own little abstraction:

// Return type: () -> Unit
fun <T> funcRef(obj: T?, function: T.() -> Unit) = { obj?.function() }

This trades a different syntax for a non-null function variable:

 // activity can be null
 val onBackPressedRef = funcRef(activity, Activity::onBackPressed)

 // Callable directly
 onBackPressedRef()
like image 85
TheOperator Avatar answered Sep 26 '22 02:09

TheOperator