Starting with Scala : Frontier Developer's Meetup December 2010

Preview:

DESCRIPTION

Slides from my presentation on getting started with Scala

Citation preview

Derek Chen-BeckerDerek Chen-BeckerSenior Network EngineerSenior Network Engineer

CPI CorporationCPI Corporation

Starting with ScalaStarting with Scala

Frontier Developers' MeetupFrontier Developers' MeetupDecember 9December 9thth, 2010, 2010Boulder, COBoulder, CO

Scala's Pedigree

Created by Martin Odersky (EPFL), of GJ, and later Javac v5 fame

Scala's History

Jan 04 Jan 05 Jan 06 Jan 07 Jan 08 Jan 09 Jan 10

1.1.

1.0

1.2.

0.0

1.3.

0.2

1.4.

0.0

2.1.

0 2.2.

02.

3.0

2.4.

02.

5.0

2.6.

0 2.7.

0

2.8.

0

2.8.

1

Scala History

2.7.1 - 2.7.7

More Info on Scala

Home page: http://www.scala-lang.org/Excellent community

scala-user@listes.epfl.chirc://chat.freenode.net/scalahttp://scala.sygneca.com/ (Wiki)

Scala in Print

Scala in the Real World

Scala and the JVM

Compiles to 100% Java BytecodeGenerally works flawlessly with JavaLeverages JIT: performance ±5% of Java

Full access to existing Java ecosystemCLR (.Net) port in progress

About This Talk

Scala 2.8.0+Significant changes to libraryI'm still coming up to speed on them

This is not a lecture

Act INo Time Like the Present

The Scala REPL

Read, Evaluate, Print, LoopYou need a JVM (1.6+ preferred) with “java” in your path or JAVA_HOME setDownload the latest binaries from http://www.scala-lang.org/downloadsUnpack wherever, go to bin subdirectoryType “scala<enter>”

Play Along at Home!

http://www.simplyscala.com/

Act IISo, What is Scala?

Three Very Common Keywords

val – defines an immutable value or referencevar – defines a mutable valuedef – defines a function/method

Scala is Concerned with Mutability

Immutable data structures reduce (but not eliminate) concurrency issuesCombined with actors make a powerful approach to parallel tasksStrong library and language support

Scala is Strongly Typed...

val foo : Int = 12

var bar : String = "twelve"

def baz (in : Int) : Double = in.toDouble

...But Can Usually Figure Types Out

val foo = 12

var bar = "twelve"

def baz (in : Int) = in.toDouble

Scala is Generic

val primes : List[Int] = List(2,3,5,7,11)

scala> primes.grouped(2).toListres16: List[List[Int]] = List(List(2, 3), List(5, 7), List(11))

Scala is Object­Oriented

class Foo { def bar () = { "bat" }}

val f = new Foo

I Mean Really Object­Oriented

scala> (12.5).min(47) res17: Double = 12.5

scala> 3825.toHexStringres18: String = ef1

scala> '5'.isWhitespaceres19: Boolean = false

Primitives are treated as 1st class objects

Scala is Functional

val greet = (name : String) => "Hello, %s!".format(name)

greet(“Fred”)res27: String = Hello, Fred!

val greet = "Hello, %s!".format(_ : String)

Scala is Functional Everywhere

def doubleMe (f : () => Any) { println(f()); println(f());}

scala> doubleMe(System.nanoTime) 15885045173037341588504517365296

Scala is Closurific

def counter (name : String) = { var i = 0; { () => i += 1 name + ":" + i } }

Scala is Concise...

public class Person { private String name; private int age;

public Person(String name, int age) { super(); this.name = name; this.age = age; }

public String getName() { return name; }

public int getAge() { return age; }

public void setAge(int age) { this.age = age; }

public int hashCode() {...} public String toString() {...} public boolean equals() {...} }

VScase class Person(name : String, var age : Int)

...But Maintains Uniform Access

case class Person(val name : String, private var curAge : Int) { def age = curAge def age_= (a : Int) { curAge = a }}

Scala is DSL­Friendly (be reasonable)

class Vector[T](data : Array[T]){ def + (that : Vector[T]) = {} def - (that : Vector[T]) = {} ... def ⊗ (that : Vector[T]) = {}}

val product = A B⊗val product = A. (B)⊗

Scala is Optional

val exists: Option[Int]= Some(42)val notHere: Option[Int] = None

scala> exists.map(_ * 2).getOrElse(12) res0: Int = 84

scala> notHere.map(_ * 2).getOrElse(12)res1: Int = 12

Scala Likes Tuples (Heterogeneous)

scala> val state = (12, "Empty", RED)state: (Int, java.lang.String, java.awt.Color) = (12,Empty,java.awt.Color[r=255,g=0,b=0])

scala> val (count, description, color) = statecount: Int = 12description: java.lang.String = Emptycolor: java.awt.Color = java.awt.Color[r=255,g=0,b=0]

Scala is XML­Friendly

def personToXml(p : Person) = <person name={p.name} age={p.age.toString} />

Scala is High­Level...

val people = List(Person("Fred", 30), Person("Ted", 25), Person("Ed", 41))

people.foreach (println)

Letting You Get to the Real Work

// One line of magic...implicit val orderPeople = Ordering.by((_:Person).age)

// ...allows powerful constructsval (oldest,youngest) = (people.max,people.min)

Act IIIScala OO Fundamentals

Packages

package net.foo { ...}

package net.foo

Imports

import java.io.Fileimport java.net._import java.awt.{Image, Color => JCol, Dialog => _}

Packages Nest...

package net.foo==

package net { package foo { ... }}

Sometimes in Unexpected Ways (< 2.8)

package net.foo { import java.net.URL}

The Scala OO Quadfecta

class object

trait

case class/object

Traits Are Good

Somewhat analogous to interfaces...

trait Comparable[T] { def < (that : T) : Boolean def <= (that : T) : Boolean def > (that : T) : Boolean def >= (that : T) : Boolean}

Traits are Really Awesome

...But they can carry implementation

trait Comparable[T <: Comparable[T]] { self : T => def < (that : T) : Boolean def <= (that : T) = this < that || this == a def > (that : T) = that < this def >= (that : T) = that <= this}

Traits can be Composed

trait Atrait Btrait C

class Base extends A with B with C

Class Linearization : Base Trait

trait Pet { def greeting : String def eat() : Unit}

Class Linearization : Extension Traits

trait Dog extends Pet { def greeting = "Woof" def eat() {...}}

trait Mute extends Pet { override val greeting = ""}

Class Linearization : Composition

class Dingo extends Dog with Mute

scala> (new Dingo).greetingres0: java.lang.String =

Scala Objects

“An object definition defines a single object of a new class” (Scala Reference, §5.4

object Friendly { var publicInt = 0 def hi = println("Hi!")}

Objects hold Static Methods

object MyApp { def main (args : Array[String]) { ... }}

Objects are Scoped VM Singletons

class Outer { object Inner { var foo = "foo" }}

Objects as Factories

object Person { def apply(name : String, age : Int) : Person = new Person(name,age)}

val fred = Person("Fred", 20)

Objects as Factories, Continued

object Person { ... def apply(name : String) : Person = new Person(name, 1)}

val babyFred = Person("Fred")

Named and Default Arguments

object Person { def apply(name : String, age : Int = 1) : Person = new Person(name,age)}

val fredBaby = Person(name = "Fred")

Case Classes (and Objects)

case class Car (name : String, gears : Int)

scala> val myCar = Car("Corolla", 4)myCar: Car = Car(Corolla,4)

scala> myCar.name res0: String = Corolla

Case Class Automation

Factory method (apply)toStringhashCodeequals (and therefore ==)Constructor params become vals, can be turned into vars

Case Class Bonii : Copy

scala> val myCar = Car("Corolla", 4)myCar: Car = Car(Corolla,4)

scala> val myOtherCar = myCar.copy(name = "Forester")myOtherCar: Car = Car(Forester,4)

Case Class Bonii : Extraction

scala> val myCar = Car("Corolla", 4)myCar: Car = Car(Corolla,4)

// “_” here means “don't bother”scala> val Car(_,gears) = myCargears: Int = 4

Act IVFunctional is Your Friend

Start With Some Basic Functions

foreachmapflatMapfilterexiststakeWhiledropWhile

Composing Functions == Power

people.flatMap(first => people.filter(_ != first). map(List(first,_)))

For Comprehensions

for (first <- people; second <- people if first != second) yield List(first,second)

Currying

def scaler (factor : Int) (value : Int) = factor * value

val times2 = scaler(2) _times2(12) // == 24

Provide N argument lists, but only use 1 to N-1 of them to define a new function

“By Name” Arguments

def myWhile (condition : => Boolean) (f : => Unit) { if (condition) { f; myWhile(condition)(f) }}

“By Name” Use Case : Logging

if (logger.isDebugEnabled) { logger.debug("Foo: " + foo)}

“By Name” Use Case : Logging

if (logger.isDebugEnabled) { logger.debug("Foo: " + foo)}

THIS SUCKS

“By Name” to the Rescue

def debug (msg : => String) { if (this.debugEnabled) { println(msg) }}

https://github.com/weiglewilczek/slf4s

Pattern Matching : Switch on Steroids

“case _” here is the default casedef literalMatch (in: Any) { in match { case 1 => doBar("One") case "test" => doBar("test") case 'x' => doBar("x") case 2.2f => doBar("float") case _ => doBar("lemon curry?") }}

Pattern Matching : Alternate Matches

Using “|” allows multi-match cases

def literalMatch (in: Any) { in match { case 1 | 2 | 3 => doBar("One to three") case "this" | "that" => doBar("the other") case _ => doBar("lemon curry?") }}

Pattern Matching : XML

def xmlMatch (in : Any) = in match { case <people>{bar @ _*}</people> => bar.foreach(println) case _ => // NOOP}

Pattern Matching : Case Classes

def caseMatch (a : Any) = a match { case Person(name, age) => println("%s is %d”. format(name,age))}

Pattern Matching : Type Matches

def typeMatch (in: Any) { in match { case i : Int => doBar("Int : " + i) case s : String => doBar(s) case _ => // NOOP }}

Pattern Matching : Generics

Erasure is not your friend

def typeMatch (in: Any) { in match { case ls : List[String] => doBar("danger!") case li : List[Int] => doBar("never happens") case _ => // NOOP }}

Pattern Matching : Guards

def guardMatch (in: Any) { in match { case i : Int if i > 12 && i < 47 => doBar("Int : " + i) case _ => // NOOP }}

Pattern Matching : Generics Workaround

Like duck tape : ugly, but effective

def typeMatch (in: Any) { in match { case ls : List[_] if ls.forall(_.isInstanceOf[String]) => doBar("Strings!") case li : List[_] => doBar("Some kind of List") case _ => // NOOP }}

More More Info on Scala

Home page: http://www.scala-lang.org/Excellent community

scala-user@listes.epfl.chirc://chat.freenode.net/scalahttp://scala.sygneca.com/ (Wiki)

Recommended