workshop scala

Post on 28-Jan-2015

127 Views

Category:

Education

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

I used these slides for a Scala workshop that I gave. They are based on these: http://www.scala-lang.org/node/4454. Thanks to Alf Kristian Støyle and Fredrik Vraalsen for sharing!

TRANSCRIPT

Scala workshop

Created byFredrik Vraalsen (fredrik@vraalsen.no)

and Alf Kristian Støyle (alf.kristian@gmail.com)

AdaptedBert Van Vreckem (bert.vanvreckem@hogent.be)

If I were to pick a language to use today other than Java, it would be

Scala.

James Gosling

Scala, it must be stated, is the current heir apparent to the Java throne. No other language

on the JVM seems as capable of being a "replacement for Java" as Scala, and the

momentum behind Scala is now unquestionable.

Charlies Olivier Nutter - JRuby lead

Though my tip though for the long term replacement of javac is Scala. I'm very impressed with it! I can honestly say if

someone had shown me the Programming in Scala book by by Martin Odersky, Lex

Spoon & Bill Venners back in 2003 I'd probably have never created Groovy.

James Strachen

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

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

public int getAge() { return this.age; }

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

public String getName() { return this.name; }

public void setName(String name) { this.name = name; }}

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

List<Person> persons = ... List<Person> adults = new LinkedList<Person>(); List<Person> kids = new LinkedList<Person>();for (Person person : persons) { if (person.getAge() < 18) { kids.add(person); } else { adults.add(person); }}

val (kids, adults) = persons.partition(_.age < 18)

String s = "!em esreveR";System.out.println(s.reverse());

val s = "!em esreveR"println(s.reverse)

=> Reverse me!

using(new BufferedReader(new FileReader("f.txt"))) { reader => println(reader.readLine())}

BufferedReader reader = null;try { reader = new BufferedReader(new FileReader("f.txt")); System.out.println(reader.readLine());} finally { if (reader != null) { try { reader.close(); } catch (IOException e) { // Exception on close, ignore } }}

I will never forget these words: "With great power comes great responsibility." This is my gift, my

curse. Who am I? I'm Spider-man.

val myList = List(1, 2, 3)val res = (10 /: myList)(_+_)

=> ??

Scala

● Object oriented and functional● Statically typed● Java compatible

● Complies to Java bytecode (and CLR)● Existing libraries/frameworks

● Better Java

Todays schedule

● Basic syntax● REPL, IDEs and setup● First class functions● Pattern matching● OO and traits● Functional programming● Higher order functions

Scala basics

;

Type definitions

Scala

s: String

i: Int

Java

String s

int i / Integer i

Variables

Scala:

val s = "Hello World"

var i = 1

private var j = 3

Java:

public final String s = "Hello World";

public int i = 1;

private int j = 3;

Methods (3)

Scala:

override def toString = ...

Java:

@Overridepublic String toString()

{...}

Classes and constructors

Scala:

class Person(val name: String)

Java:

public class Person {private final String

name;public Person(String

name) {this.name = name;

}public String getName() {

return name;}

}

Traits (= Interface + Mixin)

Scala:

trait Shape {def area: Double

}

class Circle extends Object with Shape

Java:

interface Shape {public double area();

}

public class Circle extends Object implements Shape

No “static” in Scala

Scala:

object PersonUtil { val ageLimit = 18

def countPersons( persons: List[Person]) = ...}

Java:

public class PersonUtil {public static final int

AGE_LIMIT = 18;

public static int countPersons( List<Person> persons) {

...}

}

While-loops

Scala:

while (true) {

...}

Java:

while (true) {

...}

Exceptions

Scala:

throw new Exception(“...”)

try {} catch {

case e: IOException => ...

} finally {}

Java:

throw new Exception(“...”)

try {} catch (IOException e) {

...} finally {}

Varargs

def foo(values: String*){ }

foo("bar", "baz")

val arr = Array("bar", "baz")

foo(arr: _*)

public void foo(String... values){ }

foo("bar", "baz");

String[] arr = new String[]{"bar", "baz"}foo(arr);

(Almost) everything is an expression

val res = if (foo) x else y

val res = for (i <- 1 to 10) yield i // List(1, ..., 10)

val res = try { x } catch { ...; y } finally { } // x or y

Generics

Scala:

List[String]

Java:

List<String>

Tuples

Scala:

val tuple: Tuple2[Int, String] =

(1, “apple”)

val quadruple =

(2, “orange”, 0.5d, false)

Java:

Pair<Integer, String> tuple = new Pair<Integer, String>(1, “apple”)

... yeah right... ;-)

Packages

Scala:

package mypackage

...

Java:

package mypackage;

...

Imports

Scala:

import java.util.{List, ArrayList}

import java.io._

import scala.util.Sorting._

import java.sql.{Date => SDate}

Java:

import java.util.List

import java.util.ArrayList

import java.io.*

???

???

REPL, IDE and setup

REPL: Read-Eval-Print Loop

● Command line shell for on-the-fly execution of Scala statements

● $ cd ${SCALA_HOME}/bin$ scala● Windows, e.g. C:\Program Files\Scala 2.8.0● Linux, e.g. /opt/scala or /usr/local/scala

IDE

● They are all !#$&§? compared to what you are used to with Java support● Netbeans (very good) but bad in other areas...● IntelliJ IDEA (pretty good) but slow compilation,

bonus community edition is free (with Scala)● Eclipse (not all that good) but very fast when

working

Netbeans 6.9.x installation

● Download pluginshttp://sf.net/projects/erlybird/files/nb-scala/6.9v1.1.0/

● In NetBeans "Tools" | "Plugins",

● click on "Downloaded" tab title,

● click on "Add Plugins..." button,

● choose the directory where the Scala plugins are unzipped,

● select all listed *.nbm files, following the instructions.

● Set ${SCALA_HOME} or %SCALA_HOME% environment variable

● Edit ${NETBEANS_HOME}/etc/netbeans.conf

● Add "-J-Dscala.home=/opt/scala" to netbeans_default_options

● More info: http://wiki.netbeans.org/Scala

Tasks (20 min)

● Run REPL● Windows: %scala_home%/bin/scala● Linux: scala or /opt/scala/bin/scala● Execute a few statements

● Copy & unpack '\\Helium\Public\Cursussen\Navorming Scala\ScalaTraining.zip'● into 'Documenten\NetbeansProjects' (Windows)● Into '/home/student/NetbeansProjects' (Linux)

Tasks (20 min)

● Run unit test in IDE (JUnit 4)

● Open the 'ScalaTraining' project in NetBeans

● Try to compile and test the project (should work)

● scalaexamples.intro.MyFirstTest

– Create a failing test– Make it run

● Make the two classes scalaexamples/intro/HelloWorld.scala print “Hello world”. What is the difference?

● Remove comments from @Test for the methods in scalaexamples/intro/CreateStuffTest.scala. Make tests pass.

First class functions

First class functions

val even = Function[Int, Boolean] { def apply(i: Int) = i % 2 == 0}

val even: (Int => Boolean) = (i: Int) => i % 2 == 0val even = (i: Int) => i % 2 == 0

even.apply(42) // trueeven(13) // false

First class functions

val numbers = List(1, 2, 3, 4, 5)

numbers.filter(even) // List(2, 4)

numbers.filter((i: Int) => i > 2) // List(3, 4, 5)numbers.filter(i => i > 2) // List(3, 4, 5)numbers.filter(_ > 2) // List(3, 4, 5)

Collections

numbers.filter(i => i > 2) // List(3, 4, 5)numbers.find(i => i > 2) // Some(3)numbers.exists(i => i > 2) // truenumbers.forall(i => i > 2) // false

numbers.map(i => i * 2) // List(2, 4, 6, 8, 10)

numbers.foldLeft(0) { (a, b) => a + b } // 15

Closures

val people = List(Person(“Alf”), Person(“Fredrik”))

var name = “Fredrik”val nameFilter = (p: Person) => p.name == name

people.filter(nameFilter) // Person(“Fredrik”)name = “Alf”people.filter(nameFilter) // Person(“Alf”)

Tasks (30 min)

● Open the 'first-class-functions' project ● Tests in package

scalaexamples.firstclassfunctions● Add @Test to one and one method● Follow instructions in the code● Make the tests pass

Pattern matching

myObject match { case 1 => println("First was hit") case 2 => println("Second was Hit") case _ => println("Unknown") }

myObject match { case i: Int => println("Found an int") case s: String => println("Found a String") case _ => println("Unknown") }

myObject match { case i: Int => println("Found an int") case s: String => println("Found a String") case other => println("Unknown " + other) }

myObject match { case i: Int if i == 1 => println("Found an int") case s: String => println("Found a String") case other => println("Unknown " + other) }

val res = myObject match { case i: Int if i == 1 => "Found an int" case s: String => "Found a String" case other => "Unknown " + other}

val res = myObject match { case (first, second) => second case (first, second, third) => third}

val mathedElement = list match { case List(firstElement, lastElement) => lastElement case List(firstElement, _ *) => firstElement case _ => "failed"}

def length(list: List[_]): Int = list match { case Nil => 0 case head :: tail => 1 + length(tail) }

def second_or_0(list:List[Int]) = list match { case List(_, x, _*) => x case _ => 0}

public static Integer getSecondOr0(List<Integer> list) { if (list != null && list.size() >= 2) { return list.get(1); } else { return 0; }}

Case classes

● Class types that can be used in pattern matching

● Generated into your class:● equals● hashCode● toString● getters (and optionally setters)● ++

abstract class Person(name: String)case class Man(name: String) extends Person(name)case class Woman(name: String, children: List[Person]) extends Person(name)

p match { case Man(name) => println("Man with name " + name) case Woman(name, children) => println("Woman with name " + name + " and with " + children.size + " children")}

val regex = """(\d+)(\w+)""".r val myString = ...

val res: String = myString match { case regex(digits, word) => digits case _ => "None" }

val regex = """(\d+)(\w+)""".r val myString = ...

val res: Option[String] = myString match { case regex(digit, word) => Some(digit) case _ => None }

The Option type, never again NullPointerException

● Option has two possible values● Some(value)● None

val someOption: Option[String] = Some("value")val noOption: Option[String] = None

def getValue(s: Any): Option[String]

getValue(object) match { case Some(value) => println(value) case None => println("Nothing") }

val result = getValue(object).getOrElse("Nothing")

Tasks (30 min)

● Open the 'pattern-matching' project● Tests in package

scalaexamples.patternmatching● Add @Test to one and one method● Follow instructions in the code● Make the tests pass

Object orientation andtraits

Annotations – not marker interfaces

@serializable class Person

@SerialVersionUID(1) class Person

@cloneable class Person

@remote class Service

object

● object is a “singleton” class● Call may look like static method calls in Java● Can inherit from other classes and traits● Can be passed as a reference

object MyObject { def foo = "bar"}

var baz = MyObject.foo val personObject = MyObjectbaz = personObject.foo

Companion object

● Can read the companion class' private fields ● Has to be in the same source file

class Person(private val age: Int)

object Person { def getPersonAge(p: Person) = p.age}

val personInstance = new Person(30)val age = Person.getPersonAge(personInstance)

Magical apply

class Person private(val age: Int)

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

var personInstance = Person.apply(30) personInstance = Person(30)

val myList = List(1, 2, 3)val mySet = Set(1, 2, 3)val myMap = Map(1 -> "one", 2 -> "two")

Not built in, clever use of apply

Constructors

● Always one primary constructor● Parameters are automatically instance variables● Class “body” is the primary constructors content● Auxiliary constructors MUST call or chain to primary

constructor

class MyClass(myString: String, myInt: Int)

val myOtherInt = 10 println("In main body") }

Auxiliary constructors

class MyClass(myString: String, myInt: Int) {

def this(myString: String) = this(myString, 0) def this() = { this("foo") println("In default constructor") } }

Inheritance

class MyClass(myString: String)

class MySubClass(myString: String, myInt: Int) extends MyClass(myString) {

println("MyString: '" + myString + "', MyInt: '" + myInt + "'") }

Inheritance

● Single class inheritance● Multiple trait mixins

Syntax

class Person extends AnyRef with java.io.Serializable with java.rmi.Remote

class Person extends java.io.Serializable with java.rmi.Remote

Traits

● “Multiple inheritance done right”● Implement methods● Initialized fields● Abstract methods● Abstract fields● Abstract types● Does not have constructors● Call to super → strict semantics

scala.Ordered trait

trait Ordered[A] { def compare(that: A): Int

def < (that: A): Boolean = (this compare that) < 0 def > (that: A): Boolean = (this compare that) > 0 def <= (that: A): Boolean = (this compare that) <= 0 def >= (that: A): Boolean = (this compare that) >= 0}

The Ordered trait

class Person(private val age: Int) extends Ordered[Person] {

def compare(other: Person) = this.age - other.age}

val person1 = new Person(21)val person2 = new Person(31)person1 < person2 // trueperson1 <= person2 // trueperson1 >= person2 // false

“Dynamic mixins”

class Person(age: Int) { override def toString = "my age is " + age}

trait MyTrait { override def toString = "I am sure " + super.toString}

val person = new Person(30) with MyTraitprintln(person)

=> I am sure my age is 30

is-a vs has-a

● Inheritance as usual● Easier to implement has-a● Inheritance vs composition

Tasks (30 min)

● Open 'oo-traits' project● Tests under scalaexamples

● companionobject● inheritance● traits

● Add @Test to one and one method● Follow instructions in code● Make tests pass

Functional programming

“Functional programming”

● First class functions● Pattern matching● Higher order functions

Functional programming

● Purity● Mathematical functions have no side effects

● f(x) = 2x + 3● y = sin(x)

● Mathematical functions always give same result for same input● Only immutable objects (and object graphs)

In practice

● All fields must be immutable● All methods must return something● No side-effects from method calls

● println("...") is also a side effect!

List

● head :: tail● Prepends to the head of the list● Other operations (filter, map, remove,

partition...) returns a new List instance

scala.collection.immutable

● ...or scala.collection.mutable● Pick your poison!

Scala 2.8

● Case classes get copy methods● Constructors and methods get

● named parametersdef resize(width: Int, height: Int) = { ... }resize(height = 42, width = 120)

● default parametersdef f(elems: List[Int], x: Int = 0, cond: Boolean = true)f(List(1))f(Nil, cond = false)

Strive to be pure

● Parallelization and concurrency (no synchronization)

● Usually easier to find errors (a lot less state)● Easier to test

Refactoring imperative style code def printMultiTable() { var i = 1 // row while (i <= 10) { var j = 1 // column while (j <= 10) { val prod = (i * j).toString var k = prod.length // padding while (k < 4) { print(" ") k += 1 } print(prod) j += 1 } println() i += 1 } }

1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40 5 10 15 20 25 30 35 40 45 50 6 12 18 24 30 36 42 48 54 60 7 14 21 28 35 42 49 56 63 70 8 16 24 32 40 48 56 64 72 80 9 18 27 36 45 54 63 72 81 90 10 20 30 40 50 60 70 80 90 100

Refactoring imperative style code

● Side effect: printing table● Functional style: return String

● Harder to test● How to test result of println()?

● While loop & vars● Functional style: val, for expressions, helper

functions● Helper functions can be tested separately

Functional style multiplication table

def makeRowSeq(row: Int) = for (col <- 1 to 10) yield { val prod = (row * col).toString val padding = " " * (4 - prod.length) padding + prod }

def makeRow(row: Int) = makeRowSeq(row).mkString

def multiTable = { val tableSeq = for (row <- 1 to 10) yield makeRow(row) tableSeq.mkString("\n") }

A closer look at Collections

● Overview of collection traits

http://www.decodified.com/scala/collections-api.xml

Traversable

● One abstract method:def foreach[U](f: Elem => U)

● 50+ concrete methods● Addition, mapping, conversion, copying, size info,

element retrieval, sub-collection retrieval, subdivision, element tests, folds, string operations, view

http://www.scala-lang.org/docu/files/collections-api/http://www.scala-lang.org/api/

Iterable

● Abstract method iterator● Default implementation of foreach:

def foreach[U](f:Elem => U): Unit = { val it = iterator while (it.hasNext) f(it.next())}

● Subclasses may override

● Some concrete methods● Subcollections, "zippers", comparison

Seq, IndexedSeq, LinearSeq

● Sequence: ● iterable that has a length, ● elements have fixed index position, starting with 0

● Operations:● Indexing (apply), search, addition, update, sorting,

reversal, comparison, set operations● IndexedSeq, LinearSeq

● No new operations, but different performance– LinearSeq: efficient head, tail– IndexedSeq: efficient apply, length

Sets, SortedSet

● Set = iterable that contain no duplicates● Operations for tests, addition, removal, set

operations

● SortedSet● Iterator/foreach visit elements in given ordering● Default implementation: binary tree

Maps

● Map = collection of pairs of keys and valuese.g. Map("x" -> 24, "y" -> 25, "z" -> 26)● Operations for lookup, addition/update, removal,

subcollections, transformations

Immutable collections

http://www.decodified.com/scala/collections-api.xml

Mutable collections

Higher order functions

Higher order functions

● Functions which take functions as parameters and/or return functions

Higher order functions

Short summary of first class functions:val even: (Int => Boolean) = (i: Int) => i % 2 == 0

Same type definition:def test(numbers: List[Int], f: Int => Boolean) = ...

Call:test(List(1, 2, 3), (i: Int) => i % 2 == 0)

Higher order functions

def test(numbers: List[Int], f: Int => Boolean) = numbers.map(tall => f(tall))

// List[Boolean]

Higher order functions

Functions with several parameters must list them in parenthesis:

def test(l: List[String], f: (Int, String) => Boolean)

call-by-value vs. call-by-name

● by-value: expressions are evaluated before being passed to the function

● by-name: expressions evaluated inside function● nice when computationally expensive● possible to create nice APIs

call-by-value vs. call-by-name

Example: Logging

def thisTakesTime = { println(“Slow computation”) “result”}logger.debug(thisTakesTime())

call-by-value

def debug(s: String) { println(“debug”) if (logLevel <= DEBUG) println(s)}

// Slow computation

// debug

// result

call-by-name

def debug(s: => String) { println(“debug”) if (logLevel <= DEBUG) println(s)}

// debug

// Slow computation

// result

using(new BufferedReader(new FileReader("f.txt"))) { reader => println(reader.readLine())}

BufferedReader reader = null;try { reader = new BufferedReader(new FileReader("f.txt")); System.out.println(reader.readLine());} finally { if (reader != null) { try { reader.close(); } catch (IOException e) { // Exception on close, ignore } }}

def using[T <: { def close() }, A] (closeable: T) (f: T => A) = { try { f(closeable) } finally { if (closeable != null) { try { closeable.close() } catch { case e: Exception => // Do something clever!? } } }}

Tasks (30 min)

● Open 'higher-order-functions' project● Tests in scalaexamples.higherorderfunctions● Add @Test to one and one method● Implement missing functions in PersonFilter

and so on.● Follow instructions in code● Make tests pass

Where to go next?

Advanced topics

● Type inference● Implicit conversions● Extractors● Annotations● XML● Parallel programming with Actors● Domain Specific Languages (DSLs)● GUI programming with Scala Swing

Exercises

● Solutions to exercises:http://github.com/javaBin/scala-training-code/zipball/solutions

● 99 Scala Problems:http://aperiodic.net/phil/scala/s-99/

Bert's Scala bookmarks:http://www.delicious.com/bertvv/scala

A lot of blogs

http://www.planetscala.com/

Mailing lists

scala@listes.epfl.chscala-announce@listes.epfl.ch

scala-user@listes.epfl.chscala-debate@listes.epfl.chscala-tools@listes.epfl.ch

scala-internals@listes.epfl.ch

http://www.scala-lang.org/node/199

Several books

+++http://www.scala-lang.org/node/959

Creative Commons

http://programming-scala.labs.oreilly.com/index.html

http://www.scala-lang.org/

Creative Commons Attribution 3.0 Unported

Scala Training Codehttp://github.com/javaBin/scala-training-code

git clone git://github.com/javaBin/scala-training-code

Scala Training Slideshttp://github.com/javaBin/scala-training-slides

git clone git://github.com/javaBin/scala-training-slides.git

top related