ScaLearning 1 – Closure Oddities

facebooktwitterdiggdzonestumbleuponredditdelicious


Welcome to my first ScaLearning post.

Like many developers who make the journey from Java to Scala, I often find myself amazed at how much easier it is to do some things, or how much easier it is to express myself in Scala.

“ScaLearning” will be a series of short blog-posts just documenting little tidbits I find interesting, confusing, amusing, or otherwise worthy of talking about.
 
 

ScalaWTF.txt

Back in March I created a document called “ScalaWTF.txt”. Today I randomly found it, read it, and thought to myself, “WTF?! How does that work!”. Yes, I think in ancronyms 🙂

Here’s what the document said:

scala> (1 to 5) filter{x => println("hi"); x%2==0}                          
hi
hi
hi
hi
hi
res61: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4)

scala> (1 to 5) filter{println("hi"); _%2==0}                               
hi
res62: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4)

It only took me a moment or two to remember why I found this so confusing. The two closures I supply to “filter” look nearly identical, yet they behave very differently.

I decided to dig a little deeper:

scala> val f : (Int) => Boolean = (x) => {println("hi"); x % 2 == 0 }
f: (Int) => Boolean = 

scala> f(2)                                                          
hi
res1: Boolean = true

scala> f(3)
hi
res2: Boolean = false

Interesting, so that behaves as I would expect. The “println”, being a part of the closure, is executed on each call to “f”. Now the other:

scala> val f : (Int) => Boolean = {println("hi"); _ % 2 == 0 }    
hi
f: (Int) => Boolean = 

scala> f(3)                                                   
res3: Boolean = false

scala> f(2)
res4: Boolean = true

Strange, and not what I expected. Let’s take it a step further.

scala> val f : (Int) => Boolean = {println(_); 2 % 2 == 0 }    
:5: error: missing parameter type for expanded function ((x$1) => println(x$1))
       val f : (Int) => Boolean = {println(_); 2 % 2 == 0 }
                                           ^
:5: error: type mismatch;
 found   : Boolean(true)
 required: (Int) => Boolean
       val f : (Int) => Boolean = {println(_); 2 % 2 == 0 }

So apparently, while I assumed what I was doing was passing in a closure to “f”, what I was actually doing was evaluating a block, the last element of which must be a closure. Also, only the last statement is capable of binding with the wildcard.

Based on that, the following will not work:

val f : (Int,Int) => Boolean = {println(_); _ % 2 == 0 }

But this one should:

val f : (Int,Int) => Boolean = {println("a"); _ % _ == 0 }

After trying it, the REPL proved my theory. The take-home is that using wildcards in your closure isn’t quite the same as explicitly declaring your variables.


facebooktwitterdiggdzonestumbleuponredditdelicious

Advertisements

4 comments on “ScaLearning 1 – Closure Oddities

  1. IMHO this lesson should tell you that you should avoid the _ in scala AS MUCH AS POSSIBLE it has too many different meanings.
    This works very fine:
    val f : (Int) => Boolean = (x) => {println(“hi”+x); x % 2 == 0 }
    and is nice to read

    thanks for sharing your scala experience!

    regards andreas

  2. Thanks for the comment Andreas 🙂

    I’m still deciding on how much I like using the wildcard, but I’m not sure I’m ready to discard it yet.

    A few expressions:

    /* 1 */ (1 to 5) filter( (x) => x % 2 == 0 )
    /* 2 */ (1 to 5) filter( _ % 2 == 0)
    /* 3 */ (1 to 100) reduceLeft( (x,y) => x + y )
    /* 4 */ (1 to 100) reduceLeft (_+_)

    I find 1 and 2 about equivalent, but 4 far more readable than 3.

    So the question is, where is the line? Do I blame Scala for not being obvious to someone new to the language (myself), or do I blame my lack of experience?

    To offer context, I pulled a more Scala-literate colleague aside and showed them the following two lines:
    scala> val f : (Int) => Boolean = {println("hi"); _ % 2 == 0 }
    scala> val f : (Int) => Boolean = (x) => {println("hi"); x % 2 == 0 }

    When I told him that I thought they were functionally equivalent, but that they were producing different behaviour, he told me without any real hesitation he pointed out the difference that lead to the last couple of experiments in my post. The difference in brackets was key.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s