DEV Community

loading...

Kotlin safe casting

Mahendran
Android developer, Kotlin - KMP - GraphQL enthusiast
Originally published at mahendranv.github.io Updated on ・1 min read

Kotlin safe cast operator

In multiple cases you might've came across the situation where you have to cast a global variable and check the instance beforehand.

A most common case in Android environment is to check whether the (hosting) activity implements a callback or extended from Specific one.

Before

if (activity is BaseActivity) {
   (activity as BaseActivity).hideKeyboard()
}
Enter fullscreen mode Exit fullscreen mode

After

Same can be written in sweet Kotlin syntax in a single line

(activity as? BaseActivity)?.hideKeyboard()
Enter fullscreen mode Exit fullscreen mode

From the official doc

Use the safe cast operator as? that returns null on failure.

How this is better?

In surface it might not look like a better code overhaul. As calls to activity increase in numbers, it gets better.

// CreateTweetFragment.kt
fun submit() {

  // Fire and forget API call

  if (activity is BaseActivity) {
     (activity as BaseActivity).hideKeyboard()
  }

  if (activity is TweetSubmittedCallback) {
     (activity as TweetSubmittedCallback).onTweetSubmitted()
  }
}
Enter fullscreen mode Exit fullscreen mode

We could easily cast the activity to the exact subclass and invoke both methods.

// CreateTweetFragment.kt
fun submit() {

  // Fire and forget API call

  if (activity is TwitterActivity) {
     (activity as TwitterActivity).hideKeyboard()
     (activity as TwitterActivity).onTweetSubmitted()
  }
}
Enter fullscreen mode Exit fullscreen mode

But it enforces the CreateTweetFragment to be attached to the TwitterActivity to execute both statements. Anything that is just a BaseActivity or TweetSubmittedCallback won't execute the statement even though the implementation is in place.

Prefer composition over inheritance

Now with the as? operator, both statements can be executed independent of each other.

fun submit() {

  // Fire and forget API call

  (activity as? BaseActivity)?.hideKeyboard()
  (activity as TweetSubmittedCallback)?.onTweetSubmitted()
}
Enter fullscreen mode Exit fullscreen mode

Discussion (1)

Collapse
4gus71n profile image
Agustín Tomas Larghi

Nice! I usually do something like this for getting the extras from the bundle in the onCreate. You can also do something like:

val myFoo = myBar as? Boo ?: RuntimeException("myBar should be Boo")
// myFoo is Boo here. Usually I do things like this when I know for sure that I should have a variable of type Boo. You can do things like this with Context or Bundle values.