15

The code below will not compile because the variable myType can be null. Is there a way of executing a with block for nullable types in Kotlin?

    val myType: MyType? = null
    with(myType) {
        aMethodThatBelongsToMyType()
        anotherMemberMethod()            
    }
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
memoizr
  • 2,081
  • 2
  • 18
  • 24
  • how about wrapping it in `myType != null`? Kotlin smart casts should handle it. – Geralt_Encore Mar 01 '16 at 12:53
  • 1
    Just a small remark: in Kotlin, `with` is not an operator but a function with two arguments of types `T` and `T.() -> R`, so its usage is the same to usage of any other function. See `with` documentation: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/with.html – hotkey Mar 01 '16 at 13:51
  • Thanks, I updated the title to reflect your suggestion. – memoizr Mar 01 '16 at 14:00

2 Answers2

25

You can convert a nullable type to a non-nullable type with the suffix !!:

with(myType!!) {
    aMethodThatBelongsToMyType()
    anotherMemberMethod()            
}

If the value is indeed null, it will throw a NullPointerException, so this should generally be avoided.

A better way to do this is to make the execution of the code block dependent on the value being non-null by making a null-safe call and using the apply extension function instead of with:

myType?.apply {
    aMethodThatBelongsToMyType()
    anotherMemberMethod()            
}

Yet another option is to check if the value is non-null with an if statement. The compiler will insert a smart cast to a non-nullable type inside the if-block:

if (myType != null) {
    with(myType) {
        aMethodThatBelongsToMyType()
        anotherMemberMethod()            
    }
}
Ingo Kegel
  • 46,523
  • 10
  • 71
  • 102
  • There are much more information about dealing with nulls in Kotlin, please add to answer. https://stackoverflow.com/questions/34498562/in-kotlin-what-is-the-idiomatic-way-to-deal-with-nullable-values-referencing-o – Ruslan Mar 01 '16 at 13:30
5

You could define your own with function that accepts nullables, then determines whether to actually run based on whether the object is null.

Like this:

fun <T, R> with(receiver: T?, block: T.() -> R): R? {
    return if(receiver == null) null else receiver.block()
}

Then you can call the code the way you wanted to in the example with no issues, and the result will equal null if what you pass in is null.

Or, if the code block should (and could) be run either way, even if myType is null, then you'd define it like this instead:

fun <T, R> with(receiver: T?, block: T?.() -> R): R {
    return receiver.block()
}
Jacob Zimmerman
  • 1,521
  • 11
  • 20