pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

108
Pragmatic Jonas Bonér Real-World Scala Scalable Solutions

Upload: hiroshi-ono

Post on 20-Jan-2015

901 views

Category:

Documents


0 download

DESCRIPTION

 

TRANSCRIPT

Page 1: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Pragmatic

Jonas Bonér

Real-World Scala

Scalable Solutions

Page 2: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

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

James Gosling

Page 3: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Chat app in Lift Build a multi-user, comet-based chat app About 30 lines of code Three slides worth Slides By David Pollak, creator of Lift

Page 4: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Define Messagescase class Add(who: Actor)

case class Remove(who: Actor)

case class Messages(msgs: List[String])

Page 5: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Chat Server object ChatServer extends Actor { private var listeners: List[Actor] = Nil private var msgs: List[String] = Nil def act = loop { react { case s: String => msgs = s :: msgs listeners.foreach(l => l ! Messages(msgs)) case Add(who) => listeners = who :: listeners who ! Messages(msgs) case Remove(who) => listeners -= who } } this.start}

Page 6: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Chat Comet Component class Chat extends CometActor {

private var msgs: List[String] = Nil def render = <div> <ul>{ msgs.reverse.map(m => <li>{ m }</li>) }</ul> { ajaxText("", s => { ChatServer ! s; Noop }) } </div> override def localSetup = ChatServer ! Add(this) override def localShutdown = ChatServer ! Remove(this) override def lowPriority = { case Messages(m) => msgs = m; reRender(false) }}

Page 7: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Demo

Page 8: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Scalable language

Page 9: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Unique and elegant blend of

OO FP+

Page 10: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Martin Odersky

Since 2003Sponsored by EPFL

Friendly and supportive

community

Runs on the JVM

Production ready

Pragmatic

Statically typed

Seamless Java interoperability

Page 11: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Unique and elegant blend of

is...

Page 12: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

val phonebook = Map( “Jonas” -> “123456”, “Sara” -> “654321”)phonebook += (“Jacob” -> “987654”)println(phonebook(“Jonas”))

Expressive & light-weight

Page 13: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

High-level

boolean hasUpperCase = false;for (int i = 0; i < name.length(); i++) { if (Character.isUpperCase(name.charAt(i))) { hasUpperCase = true; break; }}

Java version

Page 14: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

High-level

val hasUpperCase = name.exists(_.isUpperCase)

Scala version

Page 15: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

// Javapublic class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } public void setName(String name) { this.name = name; } public void setAge(age: int) { this.age = age; }}

Concise

// Scalaclass Person( var name: String, var age: Int)

Page 16: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Pure OO1 + 21.+(2)

123.toString()

Page 17: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Extensibleval service = actor { loop { receive { case Add(x,y) => reply(x+y) case Sub(x,y) => reply(x-y) } }}service ! Add(4, 2) 6

Page 18: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Pragmaticdef users = <users> <user role=”customer”> <name>{ user.name }</name> <password>{ user.password }</password> <email>{ user.email }</email> </user> ... </users>

Page 19: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Pragmatic

users match { case <users>{users @ _*}</users> => for (user <- users) println(“User “ + (user \ “name”).text)}

Page 20: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

“direct:a“ ==> { loadbalance roundrobin { to (“mock:a“) to (“mock:b“) to (“mock:c“) }}

Great for DSLsApache Camel

Page 21: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Scala isdeep

Page 22: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

But you don’t need to go very deep

to still have fun and be productive

Page 23: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Java

Page 24: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Tastier Java

Page 25: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Different beast

Page 26: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Composition

Page 27: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

in largeComposition

Page 28: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

building blocks

2

Page 29: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

TraitsSelf-type

&&

annotations

Page 30: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Traittrait Dad { private var children: List[Child] = Nil

def addChild(child: Child) = children = child :: children

def getChildren = children.clone}

Page 31: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Base

class Man(val name: String) extends Human

Page 32: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Plumbing

Page 33: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Static mixin composition

class Man(val name: String) extends Human with Dad

Page 34: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Static mixin compositionusage

class Man(val name: String) extends Human with Dad

val jonas = new Man(“Jonas”)

)

jonas.addChild(new Child(“Jacob”))

Page 35: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Dynamic mixin composition

val jonas = new Man(“Jonas”) with Dad

Page 36: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

jonas.addChild(new Child(“Jacob”))

Dynamic mixin compositionusage

val jonas = new Man(“Jonas”) with Dad

Page 37: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

3 different type of traits

Page 38: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

1

Page 39: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Rich interfacetrait RichIterable[A] { def iterator: Iterator[A] // contract method

def foreach(f: A => Unit) = { val iter = iterator while (iter.hasNext) f(iter.next) }

def foldLeft[B](seed: B)(f: (B, A) => B) = { var result = seed foreach(e => result = f(result, e)) result }}

Page 40: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

val richSet = new java.util.HashSet[Int] with RichIterable[Int]

richSet.add(1)richSet.add(2)

richSet.foldLeft(0)((x, y) => x + y) 3

Rich interface

Page 41: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

2

Page 42: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

trait IgnoreCaseSet extends java.util.Set[String] {

abstract override def add(e: String) = { super.add(e.toLowerCase) } abstract override def contains(e: String) = { super.contains(e.toLowerCase) } abstract override def remove(e: String) = { super.remove(e.toLowerCase) }}

Stackable modifications

Page 43: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

val set = new java.util.HashSet[String] with IgnoreCaseSet

set.add(“HI THERE“) // uppercase

set.contains(“hi there“) // lowercase true

Stackable modifications

Page 44: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

trait LoggableSet extends java.util.Set[String] {

abstract override def add(e: String) = { println(“Add :“ + e) super.add(e) }

abstract override def remove(e: String) = { println(“Remove :“ + e) super.remove(e) }}

Add another trait interceptor

Page 45: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

val set = new java.util.HashSet[String] with IgnoreCaseSet with LoggableSet

set.add(“HI THERE“) “Add: HI THERE”

Run the stack of interceptors

Prints in uppercase

Page 46: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

val set = new java.util.HashSet[String] with LoggableSet with IgnoreCaseSet

set.add(“HI THERE“) “Add: hi there”

Change the order

Prints in lowercase

Page 47: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

3

Page 48: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Trait Trait

Trait Trait

Trait

Multiple views

Base

Page 49: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Trait Trait

Trait Trait

Trait

Base

Multiple views

Page 50: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Traits

Multiplepersonalities

Page 51: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Traits

Multiple

facets

Page 52: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

class Order(val cust: Customer)

Base

Page 53: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Facetstrait Entity { ... }trait InventoryItemSet { ... }trait Invoicable { ... }trait PurchaseLimiter { ... }trait MailNotifier { ... }trait ACL { ... }trait Versioned { ... }trait Transactional { ... }

Page 54: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

val order = new Order(customer) with Entity with InventoryItemSet with Invoicable with PurchaseLimiter with MailNotifier with ACL with Versioned with Transactional

Composition

Page 55: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

What do you

need?

Page 56: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

DI

Page 57: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

this: <deps> =>

Page 58: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

this: <deps> =>

Page 59: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Dependency declarationtrait UserService { this: UserRepository => ... // provided with composition userRepository.merge(user)}

…using self-type annotation

Page 60: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
Page 61: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Duck typing

Page 62: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

if it walks like a duck…

and talks like a duck…

then it’s a duckDuck typing

Page 63: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

def authorize(target: { def getACL: ACL }) = { val acl = target.getACL ... //authorize}

Structural Typing: Duck-typing done right

Statically enforced

Page 64: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

in small

Composition

Page 65: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

“It's Time to Get Good at Functional Programming” Dr Dobb’s Journal Issue December 2008

Page 66: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

What’sall the

buzzabout?

Page 67: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

FPOrthogonal

Declarative

ReusableDeterministic

High-level

Referentiallytransparent

Immutable

Page 68: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

FP is like

Lego

Page 69: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Small reusable pieces

with input

and output

Page 70: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Unix pipes

cat File | grep 'println' | wc

Page 71: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

(x: Int) => x + 1

Functions

Page 72: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Functions as valuesval inc = (x: Int) => x + 1

inc(1) 2

Page 73: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Functions as parametershigh-order

List(1, 2, 3).map((x: Int) => x + 1) List(2, 3, 4)

Page 74: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Functions as parameterswith sugar

List(1, 2, 3).map((x: Int) => x + 1)

List(1, 2, 3).map(x => x + 1)

List(1, 2, 3).map(_ + 1)

Page 75: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Functions as closures

val addMore = (x: Int) => x + more

Page 76: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

What is more?

Page 77: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Some value outsidethe function’s lexical scopevar more = 7val addMore = (x: Int) => x + more

addMore(3) 10more = 8addMore(3) 11

Page 78: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Data StructuresFunctional

Page 79: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Immutable

Page 80: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

ListThe almighty

Page 81: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

ListsGrow at the frontInsert at front O(1)Insert at end O(n)

Page 82: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

List creation

List(1, 2, 3)

1 :: 2 :: 3 :: Nil

Page 83: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Basics

val list = List(1, 2, 3)list.head 1list.tail List(2, 3)

list.isEmpty false

Page 84: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

High-level operationsval list = List(1, 2, 3)list.map(_ + 1) List(2, 3, 4)list.filter(_ < 2) List(3)list.exists(_ == 3) truelist.drop(2) List(3)list.reverse List(3, 2, 1)list.sort(_ > _) List(3, 2, 1)List.flatten(list) List(1, 2, 3)list.slice(2, 3) List(3)...

Page 85: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

115

functions defined on List

Page 86: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Tuplesdef getNameAndAge: Tuple2[String, Int] = { val name = ... val age = ... (name, age)}

val (name, age) = getNameAndAgeprintln(“Name: “ + name)println(“Age: “ + age)

Page 87: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Otherfunctional data structures:

MapsSets

TreesStacks

Page 88: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

for (n <- names) println(n)

For comprehensions

Page 89: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

for { att <- attendees if att.name == “Fred” lang <- att.spokenLanguages if lang == “Danish” } println(att)

Like SQL queries

Find all attendees named Fred that speaks Danish

Page 90: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

val companiesForAttendeesFromLondon = for { att <- attendees if att.address.city == “London” } yield att.company

for / yield

Page 91: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

for (thing <- thingsFromHere) yield getRealThing(thing)

Everything returns a value

Page 92: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

val things = for (thing <- thingsFromHere) yield getRealThing(thing)

Everything returns a value

Page 93: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

if (fromHere) { for (thing <- thingsFromHere) yield getRealThing(thing) } else { ffor (thing <- thingsFromThere) yield thing }

Everything returns a value

Page 94: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

val things = if (fromHere) { for (thing <- thingsFromHere) yield getRealThing(thing) } else { ffor (thing <- thingsFromThere) yield thing }

Everything returns a value

Page 95: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

try { if (fromHere) { for (thing <- thingsFromHere) yield getRealThing(thing) } else { ffor (thing <- thingsFromThere) yield thing } } catch { case e => error(e); Nil }

Everything returns a value

Page 96: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

val things = try { if (fromHere) { for (thing <- thingsFromHere) yield getRealThing(thing) } else { ffor (thing <- thingsFromThere) yield thing } } catch { case e => error(e); Nil }

Everything returns a value

Page 97: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

def getThingsFromSomewhere( fromHere: Boolean): List[Thing] = { try { if (fromHere) { for (thing <- thingsFromHere) yield getRealThing(thing) } else { ffor (thing <- thingsFromThere) yield thing } } catch { case e => error(e); Nil }}

Everything returns a value

Page 98: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Patternmatching

Page 99: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

def matchAny(a: Any): Any = a match { case 1 => “one” case “two” => 2 case i: Int => “scala.Int” case <tag>{ t }</tag> => t case head :: tail => head case _ => “default” }

Pattern matching

Page 100: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Tools

Page 101: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Tools: scala/binscala

scalacfsc

scaladocsbaz

Page 102: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Tools: IDEsEclipse

NetBeansIntelliJ IDEA

EmacsJEdit

Page 103: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

BuildingMaven

AntSBT (Simple Build Tool )

Page 104: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Tools: TestingSpecs

ScalaCheckScalaTest

SUnit

Page 105: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Frameworks: WebLift

SweetSlinky

Pinky

Page 106: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Learn more

[email protected]://jonasboner.com

http://scala-lang.org

Page 107: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Professional help

http://scalablesolutions.se

Consulting Training Mentoring

Page 108: pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf

Pragmatic

Jonas Bonér

Real-World Scala

Scalable Solutions

Copyright 2009 Scalable Solutions