What is your preference: operation only on a non-null value

When working on the Binary Search Tree exercise (my iterations) I discovered that Kotlin has this nice syntax for executing a block of code only when a variable is non-null.

However, I’m not sure which variant is prevailing in the wider community. Which of the following would you use and why? If something else, please show that, too.

if (root != null) queue.addLast(root)  // 1

root?.let { queue.addLast(it) }        // 2

root?.let(queue::addLast)              // 3

I have to be honest, I do not use Kotlin, but I really hate the implicit it that Kotlin and also other languages introduced (I think nim has something like that as well).

Implicit bindings are the worst you can have.

The binding just appears out of thin air, there is no explicit assignment nor declaration.

I’m not sure if there are syntaxes that would allow for a more explicit binding, but I really would prefer 1 or 3 over 2 because of this, if I were writing Kotlin.

1 Like

In general I quite like the root?. syntax for a quick non-null check, but I’m with @NobbZ on this one in the dislike of the it implicit binding. I’d probably go for 1 or for a fourth option:

root?.let { queue.addLast(root) }

With that said, I worked professionally with Kotlin before and I imagine my coworkers would like 3, despite being too magical for me.

I would personally opt for 3, which is probably my functional background speaking.
As a functional programmer, (queue::addLast) looks exactly the same as { queue.addLast(it) }, but shorter.

BTW I personally don’t mind the it at all.

nim is more up front about it: there is a map method where you provide the var name, and mapItwhere you get it

I actually like the implicit binding, but then again, I also don’t have an issue with the context-dependence of this in JavaScript, like many people do.

The official Kotlin language authors prefer 2 and 3 over 1 and for that reason alone I would not use 1. Another reason to not use 1 is that the other two remain chainable and the first one does not.

In a Kotlin codebase I would write 3, because everyone would get it, but for “mixed developer” codebases I would probably write 2 because of its verbosity. YMMV.

Under the premise that 1 isn’t “chainable”, I’d indeed tend to use 3.

Passing functions by reference works pretty much the same everywhere, it is almost always the function name without parens and args. And especially in a team where I have developers from different languages that co-author or just cross reference the kotline code, I would strictly prefer 3 over 2, as the implicit binding is highly irritating for people that are not used to it (pun intended).

If it was an explicit binding, inline with haskells lambda syntax or JS/TS arrow functions, something short to define unnamed functions inplace, it would be so much easier. Those read different across languages but they have a common concept and do not create values from thin air.