Braces : block code and lambda confusion

Starting with this example:

class A {
	var prop: A? = null

	fun doX() {
		if(prop!=null) prop!!.print()
		else println("prop is null")
	}

	fun print(){
		println("...")
	}
}

We are trying to eliminate the use of !! (NPE hunt), so we rewrite doX():

	fun doX() {
		prop?.also { p ->
			p.print()
		} ?: println("prop is null")
	}

All is fine. Now, in the else case we need to add a second line.

With the if/else syntax we write:

	fun doXx() {
		if(prop!=null) prop!!.print()
		else {
			println("prop is null")
			println("second line")
		}
	}

Naturally, with the elvis we would write:

	fun doX() {
		prop?.also { p ->
			p.print()
		} ?: {
			println("prop is null")
			println("second line")
		}
	}

But this code is broken! The elvis right part is never called because braces means here a lambda and not a block code as with the “else” syntax.

Subtle bug, invisible and without any warning. Moreover this code has no sense since the two lines of codes in the lambda will never be called.

In this case, would it be possible to add a warning with an intention to rewrite it correctly ?

The right code is:

	fun doX() {
		prop?.also { p ->
			p.print()
		} ?: run {
			println("prop is null")
			println("second line")
		}
	}

This will prevent us from producing erroneous code that is not easy to detect and debug.

Thanks.

1 Like

I believe the return value checker will give you a warning on this

1 Like

As @kyay10 already answered the question, just as a pragmatic side-note: I found that in these situations when is usually better than if, especially as you can redefine the value as a val and therefore get rid of the nullability:

fun doX(): Unit =
    when(val p = prop) {
        null -> {
            println("null")
            println("second line")
        }
        else -> p.print()
    }

In my opinion, this is more readable than the Elvis version.

3 Likes

Unfortunately, no.

With -Xreturn-value-checker=check (or `=full`), a new warning is shown in formatGreeting() example, but no warning for the lambda never called.