% CSE 130: Fall 2012
% Crash Course in Scala
% Ranjit Jhala, UC San Diego 

# <img src="../static/scala_logo.png" width=1000 align="middle"/> 

## What is Scala ?

>- "Java + ML + Extra Magic"

>- Created by [Martin Odersky @ EPFL](http://lampwww.epfl.ch/~odersky/)
<img src="../static/martin_odersky.jpg" width=200 align="middle"/> 

>- Widely used (Twitter, FourSquare, LinkedIn, ...)

# Why Scala? 

## Why Scala: Multi Paradigm

>- Object-Functional Programming

>- Post-Functional Programming

>- Interesting blend, many exciting new features

## Why Scala: Bleeding Edge

>- Modern type system (subclassing, generics, implicits, ...) 

>- Modern concurrency (actors, collections, ...)

>- Seamless integration with Java

>- Because I wanted to learn how it works!

## Plan: Next N lectures 

Whirlwind Overview + Advanced Features

> 1. "Crash course": Expressions, Values, Types

> 2. Classes, Subtyping & Generic Polymorphism

> 3. Inheritance, Traits and Mixins

> 4. Implicits and Type-Classes

<!-- 
> 5. Laziness
> 6. Concurrency: Actors, Map-Reduce
-->


## Many Resources

Online

- Martin Odersky's [First Steps in Scala](http://www.artima.com/scalazine/articles/steps.html)

- Twitter's [Scala School](http://twitter.github.com/scala_school/)

- Matt Might's [Scala In Small Bites](http://matt.might.net/articles/learning-scala-in-small-bites/)

- API Search Engine [scalex.org](http://scalex.org)

Books

- Programming in Scala by Odersky, Spoon & Venners

- Scala for the Impatient by Horstmann


# Lets Start the "Crash Course"!

## Scala 101: Expressions & Types

Like ML, Scala is *statically* typed

>- (Almost) *everything* is an expression, which has a type 

>- Type system is rather different than ML's...


## Scala 101: Read-Eval-Print Loop

The easiest way to get started is with Scala's REPL

~~~~~{.scala}
$ scala
Welcome to Scala version 2.9.0.1 OpenJDK... 
Type in expressions to have them evaluated.
Type :help for more information.

scala> 
~~~~~

## Scala 101: Read-Eval-Print Loop

Enter expressions and have them evaluated

~~~~~{.scala}
scala> 2
res0: Int = 2

scala> 2 + 3
res1: Int = 5
~~~~~

## Everything is an "Object"

So when you type:

~~~~~{.scala}
2 + 3
~~~~~

the compiler sees the method call:

~~~~~{.scala}
2.+(3)
~~~~~

So `+` is just a method call! (as are *many* other things...)

## Everything is an "Object": Overloading

Furthermore, unlike ML (and like Java) Scala supports "overloading"

~~~~~{.scala}
scala> 2 + "cat"
res3: String = 2cat

scala> 2 + 3.0 
res4: Double = 5.0 
~~~~~

Each of these calls the appropriate method on the receiver `Int`.

## Everything is an "Object": Overloading

But don't get carried away...

~~~~~{.scala}
scala> 2 + true

<console>:8: error: overloaded method value + with alternatives:
  (x: Double)Double <and>
  (x: Float)Float <and>
  (x: Long)Long <and>
  (x: Int)Int <and>
  (x: Char)Int <and>
  (x: Short)Int <and>
  (x: Byte)Int <and>
  (x: String)String
 cannot be applied to (Boolean)
       2 + true
         ^
~~~~~

Fair enough.

## Basic Data

You have your basic built-in types...

~~~~~{.scala}
scala> 4.2 * 6.7
res8: Double = 28.14

scala> true || false
res9: Boolean = true

scala> 'c'
res10: Char = c 
~~~~~

## Basic Data

`String`s are borrowed from Java...

~~~~~{.scala}
scala> "cat"
res25: java.lang.String = cat

scala> "cat" + "dog"
res26: java.lang.String = catdog

scala> "cat" * 3 
res26: java.lang.String = catcatcat
~~~~~

## Basic Data

... and you can *take whatever you like* from Java

~~~~~{.scala}
scala> import java.util.Date
import java.util.Date

scala> new Date()
res2: java.util.Date = Thu Nov 08 17:40:50 PST 2012
~~~~~

So *every* Java library in the known universe trivially usable in Scala.

## Variables

Two ways to introduce variables

>- **Immutable** (a.k.a. The "right" way)

>- **Mutable** (a.k.a. The "if-you-must" way)

## Immutable Variables

- With the `val` keyword 

~~~~~{.scala}
scala> val x = 2
x: Int = 2
~~~~~

- `val x = e` is like Ocaml's `let x = e`

- But don't try to change (re-assign) such a variable!

~~~~~{.scala}
scala> x = x + 1
<console>:8: error: reassignment to val
       x = x + 1
         ^
~~~~~

- *Snap.*

## ... and if you absolutely must: Immutable Variables

~~~~~{.scala}
scala> var z = 1 
z: Int = 1

scala> z += 1

scala> z
res1: Int = 2

scala> z = 3
z: Int = 3
~~~~~

We will revisit `val` and `var` when we talk about objects and fields.

## Compound Data: Tuples

Scala comes equipped with modern ameneties like *tuples*

~~~~~{.scala}
scala> val t = ("cat", 12)
t: (java.lang.String, Int) = (cat,12)

scala> val t2 = ("mickey", 12, "mouse")
t2: (java.lang.String, Int, java.lang.String) 
    = (mickey,12,mouse)

scala> val t3 = ("mickey", (12, "mouse"))
t3: (java.lang.String, (Int, java.lang.String)) 
    = (mickey,(12,mouse))
~~~~~

the type is written `(T1, T2)` or `(T1, T2, T3)`

## Compound Data: Tuples

To access the tuple elements, you can use pattern matching

~~~~~{.scala}
scala> t
res7: (java.lang.String, Int) = (cat,12)

scala> val (p, q) = t
p: java.lang.String = cat
q: Int = 12
~~~~~

or the tuple *field* accessors `._1` or `._2` etc.

~~~~~{.scala}
scala> t._1
res5: java.lang.String = cat

scala> t._2
res6: Int = 12
~~~~~

## Compound Expressions

You can **sequence** expressions to get bigger expressions

~~~~~{.scala}
scala> :paste
// Entering paste mode (ctrl-D to finish)

{ println("hello world")
  2 + 8 }

// Exiting paste mode, now interpreting.

hello world
res0: Int = 10
~~~~~

*Paste-mode* lets you enter multi-line expressions in REPL

# Functions

*Many* ways to define functions 

## Functions

*Many* ways to define functions 

~~~~~{.scala}
def inc(x: Int): Int = {
  x + 1
}
~~~~~

Call a function in the usual way

~~~~~{.scala}
scala> inc(4)
res3: Int = 5
~~~~~

## Functions

No need for explicit `return` 


~~~~~{.scala}
def adder(x: Int, y: Int): Int = {
  println("thou calleth adder with (x=%d, y=%d)".format(x, y))
  val z = x + y
  println("thou getteth (z=%d)".format(z))
  z
}
~~~~~





Block evaluates to last expression

~~~~~{.scala}
scala> adder(2, 3)
thou calleth adder with (x=2, y=3)
res1: Int = 5
~~~~~

## Curried Functions

~~~~~{.scala}
def curriedAdder(x: Int)(y: Int): Int = {
  println("You called curried adder: %d %d". format(x, y))
  x + y 
}
~~~~~

which is called thus

~~~~~{.scala}
scala> curriedAdder(2)(3)
You called curried adder: 2 3
res0: Int = 5
~~~~~

## Functions with no name

A.k.a *anonymous* functions

Like Ocaml's `fun x -> e`

~~~~~{.scala}
scala> (x: Int) => x + 1 
res3: (Int) => Int = <function1>

scala> (x: Int, y: Int) => x + y 
res2: (Int, Int) => Int = <function2>
~~~~~

*Note the types of the functions*

## Functions with no name

Call by placing argument in front

~~~~~{.scala}
scala> ((x: Int) => x + 1)(8)
res3: Int = 9
~~~~~

Makes sense to bind to a name first

~~~~~{.scala}
scala> val inc = (x: Int) => x + 1
inc: (Int) => Int = <function1>

scala> inc(5)
res5: Int = 6
~~~~~

# Functions are Objects Too!

## Functions are Objects Too!

Functions are just objects with `apply` method

~~~~~{.scala}
scala> object inc { def apply(x: Int) = x + 1 }
~~~~~

Call them like so

~~~~~{.scala}
scala> inc(5)
res: Int = 6
~~~~~

## Functions are Objects Too!

Functions are just objects with `apply` method

When you **write** `f(args)` Scala **reads** `f.apply(args)`

> - Enables many fun features

> - "Uniform Access Principle" ...

## Functions are Objects Too!

Anything with `apply` can be *called*

~~~~~{.scala}
scala> val str = "megalomaniac"
str: String = megalomaniac

scala> str(2)
res: Char = g
~~~~~

# So far: Basic Data, Variables, Functions

# Next: Control Expressions


## Control Expressions

The usual suspects ...

- `if-else`

- `try-catch`

- `while`-loops

- `for`-loops 


## Control Expressions: If-Else

Put the `then` and `else` expressions inside `{...}`

~~~~~{.scala}
def fac(n: Int) = {
  if (n > 0) { n * fac (n-1) } else 1
}
~~~~~

## Control Expressions: Pattern Matching (FTW!)

Scala has pattern matching too ...

~~~~~{.scala}
def fac(n: Int): Int =
  n match {
    case n if (n > 0) => n * fac(n-1) 
    case _            => 1
  }
~~~~~

... more on this later.

## Digression: About Those Types...

(Unlike ML), you have to write down *some* types in Scala.

Function arguments and returns

~~~~~{.scala}
scala> def fac(n: Int) =
     |   n match {
     |     case n if (n > 0) => n * fac(n-1) 
     |     case _            => 1
     |   }
<console>:10: error: recursive method fac needs result type
           case n if (n > 0) => n * fac(n-1) 
~~~~~

Scala's **Local Type Inference** figures out the rest!


## Control Expressions: Try-Catch 

Put the body expression inside `{...}`

~~~~~{.scala}
import java.io.File 
 
def fileContents(file: String): List[String] = {
  val f = new java.io.File(file)
  try {
    scala.io.Source.fromFile(f).getLines().toList
  } catch {

    case e: java.io.FileNotFoundException => {
      println("WTF! No such file exists")
      List()

    }
  }
}
~~~~~

## Control Expressions: Try-Catch (contd.)

You can run it thus:

~~~~~{.scala}
scala> val lines = fileContents("lec-scalacrash.markdown")
lines: List[String] = List(% CSE 130: Spring 2012, ...)
~~~~~

and if you call it with a junk file:

~~~~~{.scala}
scala> val lines = fileContents("foobar")
WTF! No such file exists
lines: List[String] = List()
~~~~~

## Control Expressions: While-loop

Old-school `while` loops ...

~~~~~{.scala}
def fac(n: Int) = {
  var res   = 1
  var count = n
  while (count > 0) {
    res   *= count
    count -= 1
  }
  res
}
~~~~~

<!--
# Digression: Write your own Control-Expressions!

## Control Expressions: Roll Your Own While 

... can actually write `while` as a simple function!

~~~~~{.scala}
def wwhile(cond: => Boolean) (body: => Unit) {
  if (cond) { 
    body 
    wwhile(cond)(body) 
  } // what happened to the else?
}
~~~~~

## Control Expressions: Roll Your Own While 

... can actually write `while` as a simple function!

And then *call* it as:

~~~~~{.scala}
def wFac(n: Int) = {
  var res   = 1
  var count = n
  wwhile (count > 0) {
    res   *= count
    count -= 1
  }
  res
}
~~~~~

## Control Expressions: Roll Your Own!

Here's another example: *repeat-until*

~~~~~{.scala}
def repeat (body: => Unit) (cond: => Boolean) {
  body 
  if (!cond) { repeat(body)(cond) } 
}
~~~~~

## Control Expressions: Roll Your Own!

Here's another example: *repeat-until* 

Run it like this:

~~~~~{.scala}
var counter = 5
repeat { 
  counter -= 1
  println("Are we there yet?")
} (counter == 0)
~~~~~

# End Digression: Back to "built-in" Control Expressions

-->

## Control Expressions: For-loop

... and of course, `for`-loops too...

~~~~~{.scala}
scala> for (i <- 1 to 5) println(i)
1
2
3
4
5
~~~~~

## Control Expressions: For-loop

Or if you want a step...

~~~~~{.scala}
scala> for (i <- 1 to 5 by 2) println(i)
1
3
5
~~~~~
 
## Control Expressions: For-loop

Or count in the other direction ...

~~~~~{.scala}
scala> for (i <- 5 to 1 by -1) println(i)
5
4
3
2
1
~~~~~

## Control Expressions: For-loop

Actually, `for`-loops are *quite* special ...

~~~~~{.scala}
scala> for (i <- "special") println(i)
s
p
e
c
i 
a
l
~~~~~

Hmm. Whats going on?

# Scala Batteries Included: Collections


## Batteries Included: Collections

Scala bundled with with a rich set of `Collections`

- Arrays

- Lists

- (Hash) Sets

- (Hash) Maps 

- Streams ...

These are *immutable* OR *mutable*

## Batteries Included: Arrays

(Mutable) Arrays

~~~~~{.scala}
scala> val a = Array("cow", "dog", "mouse")
res14: Array[java.lang.String] = Array(cow, dog, mouse)
~~~~~

Note the type: `Array[String]`. 

Arrays have a fixed length

~~~~~{.scala}
scala> a.length
res15: Int = 3
~~~~~

## Batteries Included: Arrays

(Mutable) Arrays can be randomly **accessed**

~~~~~{.scala}
scala> a(2)
res16: java.lang.String = mouse 
~~~~~

> - "Uniform access principle" 

> - `a(2)` *read as* lookup method call `a.apply(2)`


## Batteries Included: Arrays

(Mutable) Arrays can be randomly **updated**

~~~~~{.scala}
scala> a(0) = "capuchin"

scala> a
res19: Array[java.lang.String] = Array(capuchin, dog, mouse)
~~~~~

> - "Uniform access principle" 

> - `a(0) = "capuchin"` *read as* update method call `a.update(0, "capuchin")`


## Batteries Included: For-Loops

(Mutable) Arrays can also be looped over...

~~~~~{.scala}

scala> for (animal <- a) println(animal)
capuchin
dog
mouse
~~~~~

# Loathsome "off-by-one" errors BEGONE!

# But *immutable* better if you can help it...

# Batteries Included: Lists

## Batteries Included: Lists

(Immutable) Lists

~~~~~{.scala}
scala> val xs = List(1,2,3,4)
xs: List[Int] = List(1, 2, 3, 4)

scala> val ys = List("cat", "dog", "moose", "gorilla")
ys: List[java.lang.String] = List(cat, dog, moose, gorilla)
~~~~~

Cannot change a list!!

~~~~~{.scala}
scala> ys(0) = "kite"
<console>:9: error: value update is not a member of List[java.lang.String]
       ys(0) = "kite"
       ^
~~~~~

## Batteries Included

Quite a bit like ML lists...

~~~~~{.scala}
scala> val zs = "chicken" :: ys
zs: List[java.lang.String] = List(chicken, cat, dog, moose, gorilla)
~~~~~

can be accessed via patterns

~~~~~{.scala}
def listConcat(xs: List[String]): Int =  
  xs match {
    case Nil  => "" 
    case h::t => h + listConcat(t)
  }
~~~~~

Which you can call like so:

~~~~~{.scala}
scala> listConcat(zs)
res10: chickencatdogmoosegorilla
~~~~~

## Batteries Included

(Immutable) Lists

You can also append them

~~~~~{.scala}
scala> List(1,2,3) ++ List(4,5,6)
res11: List[Int] = List(1,2,3,4,5,6)
~~~~~

and, loop over them too ...

~~~~~{.scala}

val 
scala> for (animal <- zs) println(animal)
chicken
cat
dog
moose
gorilla
~~~~~

# Batteries Included: Hash-Maps

## Batteries Included: Hash-Maps

Key-Value Maps, that can be *immutable* (by default) 

~~~~~{.scala}
scala> val numNames = Map("one" -> 1, "two" -> 2, "three" -> 3)
numNames: scala.collection.immutable.Map[java.lang.String,Int] 
        = Map(one -> 1, two -> 2, three -> 3)
~~~~~

## Batteries Included: Hash-Map Lookup

Key-Value Maps, that can be *immutable* (by default) 

You can *lookup* the value of a key much like arrays

~~~~~{.scala}
scala> numNames("three")
res12: Int = 3
~~~~~

## Batteries Included: Hash-Maps Lookup

Key-Value Maps, that can be *immutable* (by default) 

If the value doesn't exist though... **Exception**

~~~~~{.scala}
scala> numNames("nine")
java.util.NoSuchElementException: key not found: nine
.
.
.
~~~~~

## Batteries Included: Hash-Maps Membership

Key-Value Maps, that can be *immutable* (by default) 

Moral, *look before you leap* 

~~~~~{.scala}
scala> numNames.contains("nine")
res13: Boolean = false
~~~~~

or using the cleaner notation

~~~~~{.scala}
scala> numNames contains "nine"
res14: Boolean = false
~~~~~

## Batteries Included: Hash-Maps Adding Keys

Key-Value Maps, that can be *immutable* (by default) 

Would be nice to extend a map with new key-value bindings.

How do you think its done?

## Batteries Included: Hash-Maps Adding Keys

Key-Value Maps, that can be *immutable* (by default) 

Would be nice to extend a map with new key-value bindings...

~~~~~{.scala}
scala> numNames + ("nine" -> 9)
res15: scala.collection.immutable.Map[java.lang.String,Int] 
       = Map(one -> 1, two -> 2, three -> 3, nine -> 9)
~~~~~

Note the above is a **brand new map** ...

~~~~~{.scala}
scala> numNames contains "nine"
res16: Boolean = false
~~~~~

## Batteries Included: Hash-Maps Adding Keys

Key-Value Maps, that can be *immutable* (by default) 

Would be nice to extend a map with new key-value bindings ...

~~~~~{.scala}
scala> val newMap = numNames + ("nine" -> 9)
newMap: scala.collection.immutable.Map[java.lang.String,Int] 
       = Map(one -> 1, two -> 2, three -> 3, nine -> 9)
~~~~~

... Bind the result to a new map.

~~~~~{.scala}
scala> newMap("nine")
res17: Int = 9
~~~~~

<!--HEREHEREHERE -->

# Batteries Included: Mutable Hash-Maps (!)

## Batteries Included: Mutable Hash-Maps 

(pssst.) There are *mutable* Key-Value Maps too...

~~~~~{.scala}
scala> import scala.collection.mutable.HashMap

scala> val mmap : HashMap[String, Int] = HashMap()
scala> mmap += "mon" -> 1 
scala> mmap += "tue" -> 2 
scala> mmap += "wed" -> 3

scala> mmap("tue")
res18: Int = 2
~~~~~

**Note:** type parameters for the key (`String`) and value (`Int`)


# Recap: Expressions, Variables, Functions, Collections

##QUIZ: What is the value of `res`?

~~~~~{.scala}
import scala.collection.mutable.HashMap
val mutMap: HashMap[String, Int] = HashMap()
mutMap += "mon" -> 1 
mutMap += "mon" -> 2 
val res = mutMap("mon")
~~~~~

A. No value, **Type Error (cannot update val)**

B. No value, **Runtime Exception (key not found)**

C. `1: Int`

D. `2: Int`

E. `None: Option[Int]`


##QUIZ: What is the value of `res`?

~~~~~{.scala}
import scala.collection.immutable.Map
var immutMap : Map[String, Int] = Map()
var other = immutMap
immutMap = immutMap + "mon" -> 1 
immutMap = immutMap + "mon" -> 2 
val res = other("mon")
~~~~~

A. No value, **Type Error**

B. No value, **Runtime Exception (NotFound)**

C. `1: Int`

D. `2: Int`

E. `None: Option[Int]`

##QUIZ: What is the value of `res`?

~~~~~{.scala}
var mutMap : HashMap[String, Int] = HashMap()
var other = mutMap
mutMap    = mutMap + "mon" -> 1 
mutMap    = mutMap + "mon" -> 2 
val res   = other("mon")
~~~~~

A. No value, **Type Error**

B. No value, **Runtime Exception (NotFound)**

C. `1: Int`

D. `2: Int`

E. `None: Option[Int]`

# How to operate on collections?

# How to operate on collections? HOFS!

## Collections and Higher-Order Functions

All collection objects equipped with HOFs

>- filter
>- map
>- foreach
>- foldLeft, foldRight
>- and many others!

## HOFS + Collections: `filter` 

All collection objects equipped with HOFs!



~~~~~{.scala}
scala> "MaSsIvEaTtAcK".filter(c => c.isUpper)
res19: String = MSIETAK
~~~~~

Or, with equivalent, **simpler syntax** for HOFS

~~~~~{.scala}
scala> "MaSsIvEaTtAcK".filter(_.isUpper)
res20: String = MSIETAK
~~~~~

## HOFS + Collections: `filter`

All collection objects equipped with HOFs! 

~~~~~{.scala}
scala> List(1,2,3,4,5,6,7,8).filter(_ % 2 == 0)
res21: List[Int] = List(2,4,6,8) 

scala> Array(1,2,3,4,5,6,7,8).filter(_ % 2 == 0)
res21: Array[Int] = Array(2,4,6,8) 
~~~~~

## HOFS + Collections: `filter` 

With `Map`, the `filter` is over a **tuple**

~~~~~{.scala}
scala> numNames.filter(_._1.length = 3)
res24: scala.collection.immutable.Map[java.lang.String,Int] 
       = Map(one -> 1, two -> 2)
~~~~~

## HOFS + Collections: `filter` 

With a `Map`, the `filter` is over a **tuple**

(of key-value pairs)

You can use anonymous functions over tuples

~~~~~{.scala}
scala> numNames.filter({case (k, v) => k.length = 3})
res23: scala.collection.immutable.Map[java.lang.String,Int] 
       = Map(one -> 1, two -> 2)
~~~~~

## HOFS + Collections: `map`

All collection objects equipped with HOFs!

~~~~~{.scala}
scala> "MaSsIvEaTtAcK".map(_.toUpper)
res24: String = MASSIVEATTACK

scala> List(1,2,3).map(_ * 100)
res25: List[Int] = List(100, 200, 300)

scala> Array("cat", "dog", "wabbit").map(_.map(_.toUpper))
res26: Array[String] = Array(CAT, DOG, WABBIT)
~~~~~

## HOFS + Collections: `foreach` 

`foreach` is like `map` but does an action, returns `()`

~~~~~{.scala}
scala> Array("cat", "dog", "wabbit").foreach(println(_))
cat
dog
wabbit
~~~~~

val a = Array("cat", "dog", "wabbit")
for (i <- a) {println(i)}




... so whats a `for`-loop?

## HOFS + Collections: `for`-loops Revisited 

`for`-loop is just a HOF!

~~~~~{.scala}
for (a <- thing) { body }
~~~~~

is just same as

~~~~~{.scala}
thing.foreach(a => body)
~~~~~

## HOFS + Collections: `for`-loops Revisited 

So you can loop over *all* collections 

~~~~~{.scala}
scala> numNames.foreach({case (k, v) => println(k + " ~~~~~> " + v)}) 
one ~~~~~> 1
two ~~~~~> 2
three ~~~~~> 3
~~~~~~

or if you prefer

~~~~~{.scala}
scala> for ((k, v) <- numNames) { println(k + " ~~~~~> " + v) } 
one ~~~~~> 1
two ~~~~~> 2
three ~~~~~> 3
~~~~~~

## HOFS + Collections: `for`-loops Revisited 

Another example:

~~~~~{.scala}
scala> val dir = new java.io.File(".")
dir: java.io.File = .

scala> for (f <- dir.listFiles) println(f)
./slides.markdown
./scratch.markdown
./Monoid.scala
./Freq.scala
.
.
.
~~~~~

## HOFS + Collections: `for`-loops Revisited 

Sometimes, want to loop over *some* elements and skip others.

For example, to print names of all `.scala` files:

~~~~~{.scala}
scala> for (f <- dir.listFiles 
            if f.getName.endsWith(".markdown")) { println(f) }
./Monoid.scala
./Freq.scala
~~~~~

## QUIZ: HOFS + Collections: `for`-loops Revisited 

Sometimes, want to loop over *some* elements and skip others.

~~~~~{.scala}
for (x <- coll if cond) { body }
~~~~~

Is really a nice way of writing 


A. `coll.filter(x => body)`

B. `coll.filter(x => cond).foreach(x => body)`

C. `coll.foreach(x => body)`

D. `coll.foreach(x => body).filter(x => body)`



## HOFS + Collections: `for`-loops Revisited 

More often, want to **compute** a collection as a value ...

Suppose we have an `Array` of `String`s ...

~~~~~{.scala}
val words = Array("you", "are", "doing", "it", "wrong")
~~~~~

... to turn it into a **rant**

~~~~~{.scala}
scala> val rant = for (w <- words) yield w.toUpperCase
rant: Array[java.lang.String] = List(YOU, ARE, DOING, IT, WRONG)
~~~~~

... Note the output is **also** an `Array`.


## HOFS + Collections: `for`-loops Revisited 

More often, want to **compute** a collection as a value ...

Works for any collection...

~~~~~{.scala}
scala> for (w <- fileContents("lec-scalacrash.markdown") 
         yield w.toUpperCase

res: List[String] = List(% CSE 130: SPRING 2012, ...)
~~~~~

## QUIZ: HOFS + Collections: `for`-loops Revisited 

More often, want to **compute** a collection as a value ...

~~~~~{.scala}
for (x <- coll) yield expr 
~~~~~

Is really a nice way of writing 

A. `coll.foreach(x => expr)`

B. `coll.filter(x => expr)`

C. `coll.map(x => expr)`



## HOFS + Collections: `for`-loops Revisited 

More often, want to **compute** a collection as a value ...

... after some processing.

E.g., to **find** all `.scala` files in a directory

~~~~~{.scala}
scala> val scalaFiles = for (f <- dir.listFiles 
                             if f.getName.endsWith(".scala")) 
                        yield f

scalaFiles: Array[java.io.File] = Array(./Monoid.scala, ./Freq.scala)
~~~~~

## HOFS + Collections: `for`-loops Revisited 

Sometimes, want to *return* a collection...

... after some processing.

~~~~~{.scala}
scala> import scala.io.Source._
scala> val fileSizes = for (f <- dir.listFiles 
                            if f.getName.endsWith(".scala")) 
                       yield fromFile(f).length

fileSizes: Array[Int] = Array(349, 406)
~~~~~

## HOFS + Collections: `for`-loops Revisited 

Sometimes, want to *return* a collection...

... after some processing.

~~~~~{.scala}
for (x <- coll if cond) yield expr 
~~~~~

Is really another way of writing 

~~~~~{.scala}
coll.filter(x => cond).map(x => expr)
~~~~~

## HOFS + Collections: Nested `for`-loops

You can nest `for`-loops too:

~~~~~{.scala}
scala> for (i <- 1 to 3; j <- 1 to 3) yield (i, j) 


{ 
         println ("i = %d and j = %d" format(i, j))
       }
i = 1 and j = 1
i = 1 and j = 2
i = 1 and j = 3
i = 2 and j = 1
i = 2 and j = 2
i = 2 and j = 3
i = 3 and j = 1
i = 3 and j = 2
i = 3 and j = 3
~~~~~

## HOFS + Collections: Nested `for`-loops

You can nest `for`-loops too, 

and then return a collection as the result:

~~~~~{.scala}
scala> for (i <- 1 to 3; j <- 1 to 3) yield (i, j)
res: scala.collection.immutable.IndexedSeq[(Int, Int)] 
   = Vector((1,1), (1,2), (1,3), (2,1), (2,2), (2,3), (3,1), (3,2), (3,3))
~~~~~


## QUIZ: HOFS + Collections: Nested `for`-loops

Nest `for`-loops, and return a collection **after filtering**

~~~~~{.scala}
scala> val res = for (i <- List(1,2,3);  
                      j <- List(4,5,6) 
                      if i + j == 7) 
                 yield (i, j)
~~~~~

A. List()

B. List((1,6),(2,5),(3,4))

C. List(1,2,3,4,5,6) 

D. List((1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6))

E. List((1, 4), (2, 5), (3, 6))

## HOFS + Collections: Nested `for`-loops

Nest `for`-loops, and return a collection **after filtering**

Holds for any collection.

~~~~~{.scala}
scala> val res = for (i <- 1 to 3; j <- 1 to 3 if i < j) 
                 yield (i, j)

res: IndexedSeq[(Int, Int)] = Vector((1,2), (1,3), (2,3))
~~~~~

### So far, inner loop independent of outer but...


## QUIZ: HOFS + Collections: Nested `for`-loops

Inner loop **depends on** outer loop:

~~~~~{.scala}
scala> val ll = List(List(1,2), List(3,4))
scala> val res = for (xs <- ll;
                      x  <- xs) 
                 yield x 
~~~~~

What is the value of `res`?

A. List(1, 3)

B. List(List(1,2), List(3,4))

C. List((1,3), (1,4), (2,3), (2,4))

D. List(1,2,3,4)

E. List()

##  HOFS + Collections: Nested `for`-loops

Of course, you can nest `for`-loops too:

another example (wink wink) ...

~~~~~{.scala}
scala> for (w <- List("cat", "dog", "mouse"); c <- w) yield c
res: List[Char] = List(c, a, t, d, o, g, m, o, u, s, e)
~~~~~

... Note the output type is also `List` 

**Like the top-level sequence!**


##  HOFS + Collections: Nested `for`-loops

Of course, you can nest `for`-loops too:

**yet** another example (wink wink) ...

~~~~~{.scala}
scala> for (w <- Array("cat", "dog", "mouse"); c <- w) yield c
res: Array[Char] = Array(c, a, t, d, o, g, m, o, u, s, e)
~~~~~

... Note the output type is also `Array`

## HOFS + Collections: `for`-loops Revisited 

Wait a minute! Remember this? 

~~~~~{.scala}
scala> for (i <- 1 to 5) println(i)
1
2
3
4
5
~~~~~

**How does it work ?**

## HOFS + Collections: `for`-loops Revisited 

Wait a minute! Remember this? 

`1 to 5` **is a method call** `1.to(5)`

~~~~~{.scala}
scala> 1 to 5
res: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5)
~~~~~

## HOFS + Collections: `for`-loops Revisited 

If you want a **step**

~~~~~{.scala}
scala> 1 to 10 by 2   // 1.to(10).by(2)
res3: scala.collection.immutable.Range = Range(1, 3, 5, 7, 9)

scala> 10 to 1 by -1  // 10.to(1).by(-1)
res4: scala.collection.immutable.Range = Range(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

scala> 10 to 1 by -2  // 10.to(1).by(-1)
res5: scala.collection.immutable.Range = Range(10, 8, 6, 4, 2)
~~~~~


## You can do a LOT with collections!

So what does this do?

~~~~~{.scala}
List(1,2,3,4,5).foldLeft(0)((x1, x2) => x1 + x2)
~~~~~

## You can do a LOT with collections!

So what does this do?

~~~~~{.scala}
List(1,2,3,4,5).foldLeft(0)(_ + _)
~~~~~

Here, `(_ + _)` is a short hand for

~~~~~{.scala}
(x1, x2) => arg1 + arg2
~~~~~

## Btw, you can do a LOT with collections!

And, what does this do?

~~~~~{.scala}
def foo(n: Int, k: Int) = 
  (1 to k).map(_ => n).foldLeft(1)(_ * _)
~~~~~

# Put things together: Frequencies 

## Lets write a Frequency Finder

How often does a `Char` appear in a `String`

~~~~~{.scala}
def freq(str: String): HashMap[Char, Int] = {
  val freqMap = new HashMap[Char, Int]
  for (c <- str) {
    freqMap(c) = 1 + freqMap.getOrElse(c, 0)
               // if(freqMap contains c){freqMap(c)} 
               // else { 0 } 
  }
  freqMap
}
~~~~~

## Lets write a Polymorphic Frequency Finder

Lets generalize a bit. (Make it polymorphic)

~~~~~{.scala}
def freq[A](xs: Iterable[A]): HashMap[A, Int] = {
  val freqMap = new HashMap[A, Int]
  for (x <- xs) {
    freqMap(x) = 1 + freqMap.getOrElse(x, 0)
  }
  freqMap
}
~~~~~

`Iterable[A]` describes objects that can be [iterated over...](http://www.scala-lang.org/api/current/scala/collection/Iterable.html)

## Lets write a Polymorphic Frequency Finder

Can run it on `String`s

~~~~~{.scala}
scala> freq("caterpillar")
res: scala.collection.mutable.HashMap[Char,Int] 
     = Map(c -> 1, a -> 2, e -> 1, i -> 1, r -> 2, t -> 1, l -> 2, p -> 1)
~~~~~

or `List`

~~~~~{.scala}
scala> freq(List(1,2,1,13,1,2,1,3,31,12,1))
res: scala.collection.mutable.HashMap[Int,Int] 
     = Map(12 -> 1, 3 -> 1, 13 -> 1, 1 -> 5, 2 -> 2, 31 -> 1)
~~~~~

or ...

# Compiling and Running

## Compiling and Running

To make an executable, put the functions in a file 

e.g. `lec-scalacrash.scala`

~~~~~{.scala}
object Freq { ... }
~~~~~

compile with

~~~~~{.scala}
$ scalac lec-scalacrash.scala
~~~~~

and run with

~~~~~{.scala}
$ scala Freq lec1-scalacrash.markdown
$ scala Freq foo.txt
...
~~~~~

## Compiling and Running

Or now run in the REPL

~~~~~{.scala}
scala> val m = Freq("caterpillar")
scala> Freq.show(m, 1)
c : #
a : ##
e : #
i : #
r : ##
t : #
l : ##
p : #
~~~~~

