Here are my notes on learning Scala:

 

  •  Not a lot of tool support yet.  JEdit syntax highlighting works OK, as do some other editors. Eclipse plugin provides more capability, but it is slow.
  • Environment variables:
    • SCALA_HOME=/path/to/scala/dir
    • PATH (add $SCALA_HOME/bin)


Notes on the language proper:

Hello World:

object HelloWorld {
  def main(args: Array[String]) {
       println("Hello, world!")
    }
}

object defines a singleton class instance.  Every program has a function named main inside a singleton object.

def defines a function or an expression without evaluating it; it does not evaluate its RHS.

Val defines a constant; it evaluates its RHS.

Formal parameter definition should always include a type. (Array[String] for the main function.)

Function calls are call-by-value by default.  Formal parameters with ": =>" instead of just ":" are call-by-name.

Every statement returns a value.

"return val" is the same as "val" at the end of a function.

Semicolons may be used as statement terminators.

Function definitions look like this:

def funcname(parm: ParmType):FuncType = {
  statements;
}

You can omit the surrounding {} if the function body is a single statement.

You can omit FuncType if it is obvious to the compiler.

Conditions (e.g. in an if-statement) must be surrounded by parenthesis, as in C and Java.

You can nest functions (in order to scope the names).

Tail-recusion is optimized for "directly tail-recursive" calls.  e.g. This gets optimized:

    def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b)

... but this does not (due to the need to multiply AFTER the recursion returns).

    def factorial(n: Int): Int = if (n == 0) 1 else n * factorial(n 1)

Named functions can be passed by name too ("First-class functions"), as can anonymous functions.

Here is an anonymous function in use:

def blarfle(a: Int, b: Int): Int = sum((x: Int) => x * x, a, b)

The function header is "(x: Int)", so it is a function that takes a single, integer parameter. The body of the function is "x * x".

Sometimes you can get away with omitting the type (if the compiler can figure it out), as in:

def blarfle(a: Int, b: Int): Int = sum((x) => x * x, a, b)

And, whenever your argument list is just "(x)" it can be rewritten as "x" giving:

def blarfle(a: Int, b: Int): Int = sum(x => x * x, a, b)

Sometimes you'll run into a function that looks like this:

def sum(f: Int => Int): (Int, Int) => Int = {
  def sumF(a: Int, b: Int): Int =
  if (a > b) 0 else f(a) + sumF(a + 1, b)
  sumF
}

This says that 'sum' is a function that take a function (the argument 'f') that takes an Int parameter and returns an Int result;], and the function 'sum' returns a function of type "(Int, Int)=> Int)". In other words, 'sum' is a function factory that takes one function as its argument, and it generates a function that takes two Ints (and returns an Int).

One way to use sumF would be to do something like:

  def g = sum((x) => x * x)
  g(1,3)

... which calls 'sum' to generate a function that sums squares, naming the new function 'g', and then calls 'g' with 1 and 3 as parameters.

Sometimes Scala can't really tell that this is what you are trying to do, and it complans in your def of g. You solve that problem like so:

  def g = sum((x) => x * x) _
  g(1,3)

... which uses the trailing underscore to tell Scala, "Hey! Don't worry -- this call of 'sum' just returns a function and I promise to pass the right arguments to that function when I call it. (I think.)

<pFor the ultimate in brevity, you can define g and call it in a single line:</p>

sum(x => x * x)(1, 10)

The "sum(x => x * x)" generates the new (unnamed) function and the "(1, 10)" calls it with the arguments 1 and 10.

 

more soon