For those of us who use SonarQube to inspect their code on their CI, official support for Kotlin finally arrived recently and we started deploying its latest version on our servers. But as I was looking through the warnings in our very first reports and tried to fix some of them quickly, I ran into a puzzling situation concerning my lambdas.

Let’s imagine you have a certain function foo that takes two functions as parameters, and both of those parameters have default values. It could look something like this :

fun foo(lambda1: () -> Unit = {}, lambda2: () -> Unit = {}) {

lambda1()

println("----")

lambda2()

}

This function is supposed to execute both its parameter functions and print some dashes in between. For instance, if we call it like this :

foo({ println("1") }, { println("2") })

The result should be:

1

----

2

But now, what happens if I call this function with only one parameter? Will it be executed before or after the dashes are printed?

Well, as it turns out, it depends. Let’s say I call it this way:

foo({ println("A") })

The result will be:

A

----

That’s pretty much what I’d expect. I only gave one parameter without naming it, so Kotlin assumes correctly that it is the first one in the function’s signature. But if I write this line in my code, SonarQube will suggest that I take advantage of a nice Kotlin trick and move the lambda out of the parentheses. So let’s try that and change our code to this:

foo { println("A") }

Let’s run it:

----

A

Apparently, removing the parentheses changed the behavior of our code. Why is that?

Well, the problem comes from the fact that the syntactic sugar we just used (moving a lambda out of the parentheses) only applies to the last lambda in the function’s signature. In our case, it is the second lambda. So Kotlin now assumes that the parameter we provided, being out of parentheses, is our second (and last) argument, and executes it after the dashes.

Surely enough, this is a corner case but if you use RxJava in your code, you probably have some calls to a subscribe method that takes two or three lambdas (callbacks for the onNext , onComplete or onError events) and it can be tempting to wrap them in a function that would have optional arguments so you wouldn’t risk an exception if you don’t provide a handler for some types of events (especially error events). Just be warned that playing with several lambdas in your functions can be a bit tricky!

This might actually be a case where manually overloading your functions could be wise. For instance, you could choose to declare the following separate methods:

fun foo(lambda1: () -> Unit = {}) = foo(lambda1) {}

fun foo(lambda1: () -> Unit, lambda2: () -> Unit) {...}

In this case, you would be able to invoke your function with zero, one or two parameters, and calling foo() with a single lambda would always give you the same result, whether you use parentheses or not. The trade-off, however, is that you can’t invoke it with the second parameter only.

You alone can judge whether that’s acceptable or not. If you have the need for calls with either the first or the second parameter only, you would probably be better off keeping the original syntax and always use a named parameter to make sure it is obvious which argument should receive the lambda expression.

So next time SonarQube tells you to move a lambda out of parentheses, just think twice before complying. It will definitely save you some headaches to take time to double check that this tiny change in your code won’t have any unexpected side effect.