Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

A Kotlin Type Inference Puzzler

DZone's Guide to

A Kotlin Type Inference Puzzler

As useful as Kotlin's type inferencing can be, it can sometimes backfire. Let's see how and when it can go wrong and when you should just be explicit.

· Java Zone
Free Resource

Try Okta to add social login, MFA, and OpenID Connect support to your Java app in minutes. Create a free developer account today and never build auth again.

Kotlin takes type inference to the next level (at least in comparison to Java), which is great, but there are scenarios in which it can backfire on us.

The Riddle

fun foo(int: Int?) = {
    println(int)
}

fun main(args: Array<String>) {
    listOf(42).forEach { foo(it) }
}


And the question is: What does the puzzler() method print and why is it not 42? Assume that the main()method gets executed.

The answer can be found at the very end of the article.

Explanation

In Kotlin, we’ve got not only local variable type inference (which is also coming to Java) but also return value type inference when writing single-expression methods.

Which means that if we write a method:

fun foo() : String  {
    return "42"
}


We can rewrite it using the single-expression method syntax and ignore the explicit type declaration and the return keyword:

fun foo() = "42"


So, if we have a method:

fun foo(int: Int?) : Unit {
    println(int)
    return Unit
}


We could get rid of the return type declaration as well as the explicit return statement by leveraging single-expression method syntax, right? But we already know that the following doesn’t work:

fun foo(int: Int?) = {
    println(int)
}


The devil’s in the details, but everything becomes crystal clear if we specify the return type explicitly:

fun foo(int: Int?) : () -> Unit = {
    println(int)
}


If we look closely, it can be seen that we mixed two approaches here and actually defined a method that doesn’t return Unit, but a () -> Unit itself – which is simply an action that doesn’t accept any parameters and doesn’t return anything – which is semantically equivalent to returning a java.lang.Runnable instance.

This is because Kotlin utilizes curly braces not only for defining classes/methods, but also for defining lambda expressions, and { println(42) } is a valid lambda expression declaration:

val foo: () -> Unit = { println(42) }


So, our original example is simply a Higher-Order Function accepting an Int parameter and returning a function that prints it. When we return it in the forEach(), the return value just gets ignored.

So, if we want to fix our example, we have two ways to go.

Explicitly call invoke() on the returned function:

listOf(42)
  .forEach { foo(it).invoke() }


Or simply define the method properly by removing the “=” sign:

fun foo(int: Int?) {
    println(int)
}


Or by leveraging the single-expression method syntax:

fun foo(int: Int?) = println(int)


That’s why I encourage my fellow team members to declare return types explicitly.

Code snippets can be found on GitHub.

Answer

The method prints nothing.

Build and launch faster with Okta’s user management API. Register today for the free forever developer edition!

Topics:
java ,type inference ,puzzle ,lambda expressions ,tutorial

Published at DZone with permission of Grzegorz Piwowarek, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}