Scala intro: Functional programming

Our first Scala program

Here’s a simple Scala program:

object Hello112 extends App {
  println("CS112 is in Scala")
}

If we run this program (see the lecture capture for the details of how to do this in IntelliJ) we get some output:

CS112 is in Scala

We’ll talk more next time about what the object HelloCS112 extends App bit means. For now, just know that we’ll need to put it around the code we want to run–think of it sort of like

if __name__ == '__main__':
  ...

in Python.

Programming in Scala: Translating from Python

The program we’ve written above isn’t very interesting! Let’s translate a few of the programs we’ve written previously from Python to Scala in order to see what’s different (and what’s the same!).

When we were talking about breaking down problems into subtasks, we talked about the rainfall problem: given a list of sensor readings, return the average of the non-negative readings in the list before the special number -999. We came up with a couple of different solutions in Python; here’s one of them:

def average_rainfall(readings: list) -> float:
  number_of_readings = 0
  total_rainfall = 0
  for reading in sensor_input:
    if reading == -999:
      return total_rainfall / number_of_readings
    elif reading >= 0:
      number_of_readings += 1
      total_rainfall += rainfall

We can translate this program into Scala:

object Rainfall extends App {
  def averageRainfall(readings: List[Double]): Double = {
    var numberOfReadings = 0
    var totalRainfall = 0.0
    for (reading <- readings) {
      if (reading == -999) {
        return totalRainfall / numberOfReadings
      }
      else if (reading >= 0) {
        numberOfReadings += 1
        totalRainfall += reading
      }
    }
    throw new Exception("No -999 found in list")
  }

  println(averageRainfall(List(1, 2, -1, -999, 4)))
}

The good news is that this code looks pretty similar to the corresponding Python code! There are, however, some important differences. In class we constructed the Scala program step-by-step and talked about each major difference. Besides little differences in notation (for instance, for (reading <- readings) instead of for reading in readings), the big differences we see between the two programs have to do with types.

Types

Scala is a statically-typed programming language. This means that before Scala runs a program, it makes sure that every value in the program has a type that makes sense. We’ll see more about what this means as we write more Scala, but for this program it has a couple of implications:

  • We had to write List[Int] instead of just List. Scala needs to know what kind of list averageRainfall expects.
  • We had to do something in the case when we never find -999 in the list. In Python, we simply ignored this case (and our function would end up returning None); in Scala, we need to either throw an exception or return some reasonable default value (such as 0.0, or the current average).

So far, this static typing situation seems like sort of a bummer! Scala is making us jump through these annoying extra hoops before we can even run our program–what’s the point? The second change above–handling the case where the list doesn’t contain -999–is a good example of the tradeoffs of statically typed languages. Python lets us return None in that case, and as long as we never call the function on a “bad” list (i.e., one that doesn’t contain -999) everything will work fine. But if we do call the function on such a list, our program might go wrong in a way we haven’t anticipated! For instance, let’s say we want to print out the average value (to a log file, maybe, or even to a website). If we had called the function on a bad list, we’ll end up printing out “None”–which is almost certainly not what a user expects!

Scala, on the other hand, makes us dot our “i’s” and cross our “t’s”. We have to actually handle the bad list case (even if that handling just means throwing an exception). This means that we’ll never end up printing out a weird value.

So, is the additional work it takes to get through the static type checker worth it? Computer scientists have been arguing about that very question for decades! Personally, I really like dynamically-typed (the opposite of statically-typed) languages like Python when I’m writing short programs for things like data analysis or text processing; I generally prefer statically-typed languages when I’m writing larger programs.