Learning Scala? Learn the Fundamentals First

A few weeks back I gave my talk at JavaOne 2011 titled “The Scala Language Tour”, if you’re at all interested you can grab the slides and examples from github.

The session was very well received, my only enemy was time! Given 1 hour, how does one give 170+ people a taste of all that’s Scala without completely starving them of details? Lots and lots and lots of dry-runs of your presentation, that’s how. I must have iterated my talk a dozen or more times. I just couldn’t bring myself to trimming any more fat. The short story is, I could have used 5-10 more minutes. A crucial set of slides had to be omitted concerning the “Tuple” in Scala.

Tuple?

The Tuple is such a simple concept and it winds up being fundamental. The trick is recognizing their various uses throughout code.  One of the first slides I show is of this rather “toy problem”:

Believe it or not this is a really simple example

I chose this example because it shows off almost everything you need to know in order to get started with Scala.  How so you may ask?  Well, it demonstrates the use of:

  • Two Fundamental Syntax Rules
  • Higher-Order Functions
  • Anonymous Function Literals
  • Type Inference
  • Tuples

Fundamental Syntax Rules

First of all there are some syntax rules in Scala which, if not studied early enough in your learning of the language, could really throw you for a loop.  In the example above, two such rules are at play (three if you count the creation of a Tuple using only parenthesis, more on that later):

  1. A member function of a Class or Trait which accepts exactly one parameter can use a space instead of a dot when calling the function and use braces instead of parenthesis to surround the one parameter the function accepts
  2. The last expression of a function is it’s return value
So in our example:
   m.map { t => val (s,i) = t; (s, i+1) }
The instance “m” has a function called “map” which takes one parameter.  Instead of using the typical parenthesis characters (…) to contain the parameter, we use braces {…}.  Why?  Mostly because syntactically this looks nicer.  In fact, let’s rewrite our compressed example as follows:
   m map { 
     t => 
        val (s,i) = t
        (s, i+1)
   }

I got rid of the dot between the instance variable “m” and the function “map”.  I also uncompressed the code a bit by removing  the semicolon and replacing it by a newline. Semicolons are only needed in Scala when you want to write two separate expressions on the same line.

Higher-order Functions

One of the tennets of Functional Programming (FP) is Higher-Order functions.  Scala being a language which supports FP has them.  So what are they?  Well, they are functions that can accept another function as a parameter, or return another function as a value.
Remember how I applied the first of the two syntax rules above?  I could only do that  because “map” is a function that takes one parameter.  The type of that parameter is itself a Function.  So “map” is a higher-order function; in this case, a function that takes a function as a parameter.


Anonymous Function Literals

You might be scratching your head and saying to yourself: “map doesn’t appear to take a function at all but rather it seems to be passed a block of code!”.  While Scala does facilitate such things via named-parameters, that’s not what is happening in the example.  Instead, a Function Literal is being created.  You can think of Function Literals as Anonymous Functions.  Where the normal syntax for defining a named function in Scala looks like this:
   def foo(x: Int): String = "You passed me a: " + x
A function literal does away with the name of the function and instead you can just inline the parameter and the function body like so:
   (x: Int) => "You passed me a: " + x
If we weren’t passing that function as a parameter to another function, we might just as well assign it to a variable for later usage:
   val bar = (x: Int) => "You passed me a: " + x
So getting back to our original example, everything between the braces is a function literal:
   m map { 
      t =>   
         val (s,i) = t
         (s, i+1)
   }

You’ll notice two things here, the first being we never did specify a type for the parameter “t”, and secondly where the heck does the parameter “t” come from?  The map function holds the key.  The map function expects, as it’s parameter, a function and that function should accept a parameter who’s type is compatible with the parametric type specified in the Class that “m” is an instance of.  Say waaaaht?  Before I explain what that all meant, we have to cover two topics: Type Inference and The Tuple

Type Inference

Scala is particularly clever about inferring types, the benefit being the developer can become very lazy and omit types when Scala can infer them.  Let’s see a simple example:

   val s = "I'm a String"

Here, Scala can infer that you want “s” to be of type String, because you’re assigning it a literal of type String.  In our example:

   m map { 
      t =>   
         val (s,i) = t
         (s, i+1)
   }

Scala needs to infer the type of “t” because we haven’t explicitly specified it, but how will it do that?  Well, remember I said: The map function holds the key?  Let’s take a look at the map function’s signature:

   def map [B] (f: (A) => B): List[B]1

What the map function’s definition is indicating is that it expects a function, which it will rename as “f” and that function takes a type “A” as an argument, that is,  A could be an Int, String, Foo, we don’t know until map is used.  The A type placeholder is presumably defined at the Class or Trait level for the Class or Trait “m” is an instance of.

 class List[A] ... {
      def map [B] (f: (A) => B): List[B] {...}
      .
      .
      . 
   }

Now, there’s nothing to say that the types A and B can’t actually be the same types when map is used.  For example, if “m” were declared as a List[Int] and you pass it’s map function a function which returns an Int, then map will pass you back another List[Int].  Both A & B == Int in this scenario.

Getting back to our original problem, that is, how Scala infers the type of “t”; it does so by looking at the function type of the “f” parameter.  t’s type will be inferred as A (whatever that might be).  So long as the mapping function you pass it treats it “like an A”, you’re good to go.

Tuples

In the example, which I will repeat below (I don’t want you to have to scroll) there are two instances where Tuples are being used.  A Tuple is “unpacked” and a new Tuple is created. In fact, that’s all the function does really.

   m map { 
      t => 
         val (s,i) = t // 1
         (s, i+1) // 2
   }

As a developer of the code above we had knowledge of the fact that m contains a bunch of Tuples.  In this case m was defined as List[Tuple2[String, Int]].  A List that contains a Tuple, and that Tuple is made up of two components.  The first component a String, the second component is an Int.

In step 1, we unpack the components of the Tuple into the variables “s” for the first component and “i” for the second.  Notice once again we’re letting Scala infer the types of “s” and “i” from what it can gleam of the type “A”.

In step 2, we add 1 to the “i” value and then repack the Tuple.  We do this in Scala by using a comma delimited list of values surrounded with parenthesis. (Bonus Round: (a,b,c) would resolve to the type Tuple3[...], (a,b,c,d) Tuple4[...] and so on)

Remembering back to the second “Fundamental Syntax Rule”, we see that the last executable statement of a Function is its return value.  Since the last executable statement in our Anonymous Function is a Tuple, that’s the return value (and type) of the function.  The B type, is Tuple2[String,Int], in this case.

Conclusion

Can you guess then what the code sample does?  Assuming map returns a List of the things which are the output values from the function you pass it, it looks to me like you get a new List where the second component of each Tuple in the original list (re: “m”) has its value incremented by 1.

What was the biggest mistake I made when I first started learning Scala? I jumped in without looking. I felt I could just “pickup” the language, like a C# developer might pickup Java. So the point I’m trying to make is to start off in Scala by understanding some core concepts. If you do, the veil of the Matrix is lifted and you start to free your mind of the syntax which you aren’t yet used to.

Programming in Scala 2ed

Programming in Scala 2ed

I should mention, as I’ve been working on The Scala Language Tour my “book of reference” has been Programming in Scala 2nd Edition by Odersky (the language creator), Spoon & Venners.  It’s an invaluable resource for really understanding Scala and getting to the heart of the syntax and concepts which make you scratch your head when you’re new to the language.  I can’t say enough good things about it, it’s completely worth grabbing a copy for yourself.

Footnotes

  1. The map signature in Scala is actually a bit more complicated than what is depicted here. For sake of not mudding the waters with a lot of detail, the spirit of the map function is demonstrated instead

Author: craig

Share This Post On
  • doofus

    Might have been a good reading if I could read it. A light gray font on a white back really sucks.

    • craig

      I’ll play around with it. In the meantime the “Readability” plugin for the various browsers is good for these situations

    • craig

      There you go, hope that’s a bit easier on the eyes

      • http://www.google.com/profiles/vkelman Vladimir Kelman

        Craig, still virtually impossible to read (without Readability plugin). What makes such a bad font choice?

      • craig

        The font is part of the theme I chose, it does have customizable fonts though. Is it the font itself that bugs you, the size, the colour, or all of the above?

      • craig

        Hokay, theme colour picker wasn’t updating the underlying style sheet. I hardcoded in a darker value for the font

  • Pingback: Learning Scala? Learn the Fundamentals First « Another Word For It

  • opensas

    very good article, but I wonder if it’s possible to do something like:


    m map { t =>
    (t.key, t.value + 1)
    }

    I think it would be more readable and it would explicify it’s purpouse

    saludos

    sas

    • craig

      If it’s a list of just plain old Tuple2, then the best you could do is:

      m map { t =>
      (t._1, t._2 + 1)
      }

  • Erik

    Hi Craig, here’s another way of deconstructing the tuple that I think is a bit more readable:

    tuples.map { case (s,i) => (s,i+1) }

    • craig

      Erik, that’s a nice alternative. I love the interpolation powers of the case statement!

  • Pablo

    Or you could do it like so:

    m map {
    (_._1, _._2+1)
    }

    But that would scare the hell out of anyone unfamiliar with Scala’a syntactic sugars.

    • craig

      Indeed Pablo, which brings up a good point. A lot of people new to Scala argue that – because there are so many ways to skin a cat – it makes for unmaintainable code. But as is the theme of this post, once you learn the Fundamentals of the language you just recognize what’s going on in each situation.

  • Pingback: What’s in a Scala For Comprehension? | Craig Tataryn's .plan

  • Pingback: Learning the fundamentals of Scala - Devalot

  • Rossen Stoyanchev

    Craig

    The current API docs shows the map function as:

    def map [B] (f: ((A, B)) ⇒ B): Map[B]

    vs the one you have in the post:

    def map [B] (f: (A) => B): List[B]1

    What gives?

  • Pingback: Scala: Links, News And Resources (2) | Angel "Java" Lopez on Blog

  • abuabdul

    Nicely explained, Thanks. I agree to the point that we need to understand the core concepts before we dive into the hardrock code samples. I agree to join with you to emphasize ‘Programming in Scala’ is loads of in-depth details for scala enthusiasts.