Search code examples
scalafunction-literal

how to simplify scala's function literal like this?


I'm new to scala and trying to write a function literal that check whether a given integer is odd or not. my first attempt is:

val isOdd = (x:Int) => (x & 1) == 1

it works great, and, since the parameter x only appears once within this function literal, I'm tempted to use the "_" notation to simplify it further, like this:

val isOdd = ((_:Int) & 1 ) == 1

however this time the compiler complains :

warning: comparing a fresh object using `==' will always yield false
val isOdd = ((_:Int) & 1 ) == 1

what does this warning mean? why does the compiler recognize ((_ :Int) & 1) as fresh object rather than a bitwise operation that results in a value? is there any way to write this function literal using the "_" notation?


Solution

  • The problem is basically that Scala needs to tell the difference between

    val isOdd = ((_:Int) & 1 ) == 1
    

    where you want everything to the right of the equals sign to be a lambda, and

    val result = collection.map( _ + 1 )
    

    where you want only the stuff inside the parentheses to be a lambda

    Scala has decided that when you use the underscore to create a lambda, that it's going to pick the innermost set of parentheses as the boundaries of that lambda. There's one exception: (_:Int) doesn't count as the innermost parentheses because its purpose is only to group they type declaration with the _ placeholder.

    Hence:

    val isOdd = ((_:Int) & 1 ) == 1
                ^^^^^^^^^^^^^^
                this is the lambda
    
    val result = collection.map( _ + 1 )
                                ^^^^^^^
                                this is the lambda
    
    val result = collection.map(( _ + 1) / 2)
                                ^^^^^^^^
                                this is the lambda
                                and the compiler can't infer the type of the _
    
    val result = somemap.map(( _ + 1) / 2 * _)
                             ^^^^^^^^
                             this is an inner lambda with one parameter
                             and the compiler can't infer the type of the _
                             ^^^^^^^^^^^^^^^^^
                             this is an outer lambda with one parameter
    

    This last case lets you do things like

    _.map(_ + 1)
    

    and have that get translated into

    x => x.map( y=> y + 1 )