The Seductions of Scala Dean Wampler dean@deanwampler.com - - PowerPoint PPT Presentation

the seductions of scala
SMART_READER_LITE
LIVE PREVIEW

The Seductions of Scala Dean Wampler dean@deanwampler.com - - PowerPoint PPT Presentation

The Seductions of Scala Dean Wampler dean@deanwampler.com @deanwampler polyglotprogramming.com/talks programmingscala.com Tuesday, July 20, 2010 <shameless-plug/> Co-author, Programming Scala programmingscala.com 2 Tuesday, July


slide-1
SLIDE 1

The Seductions

  • f Scala

Dean Wampler dean@deanwampler.com @deanwampler polyglotprogramming.com/talks programmingscala.com

Tuesday, July 20, 2010
slide-2
SLIDE 2

Co-author, Programming Scala

programmingscala.com

2

<shameless-plug/>

Tuesday, July 20, 2010

Available now from oreilly.com, Amazon, etc.

slide-3
SLIDE 3

Why do we need a new language?

3

Tuesday, July 20, 2010

I picked Scala in late 2007 to learn because I wanted to learn a functional language. Scala appealed because it runs on the JVM and interoperates with Java...

slide-4
SLIDE 4

#1 We need Functional Programming …

4

Tuesday, July 20, 2010

First reason, we need the benefits of FP.

slide-5
SLIDE 5

… for concurrency. … for concise code. … for correctness.

5

Tuesday, July 20, 2010
slide-6
SLIDE 6

#2 We need a better Object Model …

6

Tuesday, July 20, 2010
slide-7
SLIDE 7

… for composability. … for scalable designs.

7

Tuesday, July 20, 2010
slide-8
SLIDE 8

Scala’s Thesis: Functional Programming Complements Object-Oriented Programming

Despite surface contradictions...

8

Tuesday, July 20, 2010

We think of objects as mutable and methods as state-modifying, which is often appropriate. But using functional idioms reduces bugs and

  • ften simplifies code. You can make your objects immutable, too!
slide-9
SLIDE 9

But we want to keep our investment in Java/C#.

9

Tuesday, July 20, 2010
slide-10
SLIDE 10

Scala is...

  • A JVM and .NET language.
  • Functional and object oriented.
  • Statically typed.
  • An improved Java/C#.

10

Tuesday, July 20, 2010
slide-11
SLIDE 11

Martin Odersky

  • Helped design java generics.
  • Co-wrote GJ that became

javac (v1.3+).

  • Understands Computer

Science and Industry.

11

Tuesday, July 20, 2010

Odersky is the creator of Scala. He’s a prof. at EPFL in Switzerland. Many others have contributed to it, mostly his grad. students. GJ had generics, but they were disabled in javac until v1.5.

slide-12
SLIDE 12

Everything can be a Function

12

Tuesday, July 20, 2010
slide-13
SLIDE 13

Objects as Functions

13

Tuesday, July 20, 2010
slide-14
SLIDE 14

14

class Logger(val level:Level) { def apply(message: String) = { // pass to logger system log(level, message) } }

Tuesday, July 20, 2010
slide-15
SLIDE 15

class Logger(val level:Level) { def apply(message: String) = { // pass to logger system log(level, message) } }

15

makes “level” an immutable field class body is the “primary” constructor method

Tuesday, July 20, 2010 Note how variables are declared, “name: Type”.
slide-16
SLIDE 16

class Logger(val level:Level) { def apply(message: String) = { // pass to logger system log(level, message) } }

16

name : Type

Tuesday, July 20, 2010 Note how variables are declared, “name: Type”.
slide-17
SLIDE 17

val error = new Logger(ERROR)

17

class Logger(val level:Level) { def apply(message: String) = { // pass to logger system log(level, message) } } … error(“Network error.”) error’s type inferred

Tuesday, July 20, 2010 After creating an instance of Logger, in this case for Error logging, we can “pretend” the object is a function!
slide-18
SLIDE 18

val error = new Logger(ERROR)

18

class Logger(val level:Level) { def apply(message: String) = { // pass to logger system log(level, message) } } … error(“Network error.”) “function object” apply is called

Tuesday, July 20, 2010 Adding a parameterized arg. list after an object causes the compiler to invoke the objectʼs “apply” method.
slide-19
SLIDE 19

Put an arg list after any object, apply is called.

19

Tuesday, July 20, 2010 This is how any object can be a function, if it has an apply method. Note that the signature of the argument list must match the arguments specified...
slide-20
SLIDE 20

Everything is an Object

20

Tuesday, July 20, 2010
slide-21
SLIDE 21

Int, Double, etc. are true objects.

21

But they are compiled to primitives.

Tuesday, July 20, 2010 This is how any object can be a function, if it has an apply method. Note that the signature of the argument list must match the arguments specified...
slide-22
SLIDE 22

Functions as Objects

22

Tuesday, July 20, 2010
slide-23
SLIDE 23

First, About Lists

The same as this “list literal” syntax:

23

val list = List(1, 2, 3, 4, 5) val list = 1 :: 2 :: 3 :: 4 :: 5 :: Nil no new

Tuesday, July 20, 2010 We build up a literal list with the “::” cons operator to prepend elements, starting with an empty list, the Nil “object”. “::” binds to the right, so the second form shown is equivalent to the first. Note the “operator notation”; x.m(y) ==> x m y
slide-24
SLIDE 24

val list = Nil.::(5).::(4).::( 3).::(2).::(1) val list = 1 :: 2 :: 3 :: 4 :: 5 :: Nil empty list Any method ending in “:” binds to the right!

24

“cons”

Tuesday, July 20, 2010
slide-25
SLIDE 25

“hello” + “world” is actually just

25

“Operator” Notation

“hello”.+(“world”)

Tuesday, July 20, 2010 Note the “operator notation”; x.m(y) ==> x m y. Itʼs not just a special case backed into the language grammar; itʼs a general feature of the language you can use for your classes.
slide-26
SLIDE 26

“hello” compareTo “world” is actually just

26

Similarly

“hello”.compareTo(“world”)

Tuesday, July 20, 2010 Note the “operator notation”; x.m(y) ==> x m y. Itʼs not just a special case backed into the language grammar; itʼs a general feature of the language you can use for your classes.
slide-27
SLIDE 27

val map = Map( “name” -> “Dean”, “age” -> 39)

Oh, and Maps

Tuesday, July 20, 2010 Maps also have a literal syntax. Is this a special case in the language grammar?
slide-28
SLIDE 28

val map = Map( “name” -> “Dean”, “age” -> 39)

Oh, and Maps

No, just method calls...

28

“baked” into the language grammar?

Tuesday, July 20, 2010 Scala provides mechanisms to define convenient “operators” as methods, without special exceptions baked into the grammer (e.g., strings and “+” in Java).
slide-29
SLIDE 29

val map = Map( “name” -> “Dean”, “age” -> 39)

Oh, and Maps

29

An “implicit conversion” converts a string to a type that has the -> method.

Tuesday, July 20, 2010 We canʼt discuss implicit conversions here, but see the extra slides which discuss how implicits work with and example of they might be used in a DSL.
slide-30
SLIDE 30

Classic Operations on Functional Data Types

30

List, Map, ...

map fold/ reduce filter

Tuesday, July 20, 2010

Collections like List and have a set of common operations that can be used on them.

slide-31
SLIDE 31

Back to functions as

  • bjects...

31

Tuesday, July 20, 2010
slide-32
SLIDE 32

32

list map { s => s.toUpperCase } // => "A" :: "B" :: Nil val list = “a” :: “b” :: Nil

Tuesday, July 20, 2010 Letʼs map a list of strings with lower-case letters to a corresponding list of uppercase strings.
slide-33
SLIDE 33

33

list map { s => s.toUpperCase } map called on list function argument list function body map argument list “function literal” No () and ; needed!

Tuesday, July 20, 2010 Note that the function literal is just the “s => s.toUpperCase”. The {…} are used like parentheses around the argument to map, so we get a block-like syntax.
slide-34
SLIDE 34

34

list map { s => s.toUpperCase } list map { (s:String) => s.toUpperCase } Explicit type

Tuesday, July 20, 2010 Weʼve used type inference, but hereʼs how we could be more explicit about the argument list to the function literal.
slide-35
SLIDE 35

So far, we’ve used type inference a lot...

35

Tuesday, July 20, 2010
slide-36
SLIDE 36

How the Sausage Is Made

class List[A] { … def map[B](f: A => B): List[B] … }

36

Declaration of map The function argument Parameterized type (like <A> in Java)

Tuesday, July 20, 2010 Hereʼs the declaration of Listʼs map method (lots of details omitted…).
slide-37
SLIDE 37

How the Sausage Is Made

trait Function1[A,R] extends AnyRef { def apply(a:A): R … }

37

No method body: => abstract like an “abstract” class Java’s “Object”

Tuesday, July 20, 2010 We look at the actual implementation of Function1 (or any FunctionN). Note that the scaladocs have links to the actual source listings. (Weʼre omitting some important details…) The trait defines an abstract method “apply”. Traits are a special kind of abstract class/interface definition, that promote “mixin composition”. (We wonʼt have time to discuss…)
slide-38
SLIDE 38

(s:String) => s.toUpperCase

38

becomes: new Function1[String,String] { def apply(s:String) = { s.toUpperCase } } Compiler generates an anonymous class

What the Compiler Does

No “return” needed

Tuesday, July 20, 2010 You use the function literal syntax and the compiler instantiates an anonymous class using the corresponding FunctionN trait, with a concrete definition of apply provided by your function literal.
slide-39
SLIDE 39

39

list map {s => s.toUpperCase} val f = new Function1[…,…] { def apply(s:String) = { s.toUpperCase } } list map {s => f(s)} using a function value Alternative

Tuesday, July 20, 2010 Back to where we started. Note again that we can use “{…}” instead of “(…)” for the argument list (i.e., the single function) to map.
slide-40
SLIDE 40

Since functions are objects, they could have state...

40

Tuesday, July 20, 2010
slide-41
SLIDE 41

41

class Counter[A](val inc:Int =1) extends Function1[A,A] { var count = 0 def apply(a:A) = { count += inc a // return input } } val f = new Counter[String](2) val l1 = “a” :: “b” :: Nil val l2 = l1 map {s => f(s)} println(f.count) // 4 println(l2) // List(“a”,”b”)

Tuesday, July 20, 2010 Back to where we started. Note again that we can use “{…}” instead of “(…)” for the argument list (i.e., the single function) to map.
slide-42
SLIDE 42

Succint Code

42

A few things we’ve seen so far.

Tuesday, July 20, 2010 Weʼve seen a lot of syntax. Letʼs recap a few of the ways Scala keeps your code succinct.
slide-43
SLIDE 43

same as

"hello" + "world" "hello".+("world")

Infix Operator Notation

Great for DSLs!

43

Tuesday, July 20, 2010 Syntactic sugar: obj.operation(arg) == obj operation arg
slide-44
SLIDE 44

Type Inference

44

// Java HashMap<String,Person> persons = new HashMap<String,Person>(); vs. // Scala val persons = new HashMap[String,Person]

Tuesday, July 20, 2010 Java (and to a lesser extent C#) require explicit type “annotations” on all references, method arguments, etc., leading to redundancy and noise. Note that Scala use [] rather than <>, so you can use “<“ and “>” as method names!
slide-45
SLIDE 45

45

// Scala val persons = new HashMap[String,Person] no () needed. Semicolons inferred.

Tuesday, July 20, 2010 Other things arenʼt needed...
slide-46
SLIDE 46

User-defined Factory Methods

46

val persons = Map ( “dean” -> deanPerson, “alex” -> alexPerson) no new needed. Returns an appropriate subtype.

Tuesday, July 20, 2010 Factory methods on the cheap...
slide-47
SLIDE 47

class Person { private String firstName; private String lastName; private int age; public Person(String firstName, String lastName, int age){ this.firstName = firstName; this.lastName = lastName; this.age = age; } public void String getFirstName() {return this.firstName;} public void setFirstName(String firstName) { this.firstName = firstName; } public void String getLastName() {return this.lastName;} public void setLastName(String lastName) { this.lastName = lastName; } public void int getAge() {return this.age;} public void setAge(int age) { this.age = age; } }

Typical Java

47

Tuesday, July 20, 2010 Typical Java boilerplate for a simple “struct-like” class. Deliberately too small to read...
slide-48
SLIDE 48

class Person( var firstName: String, var lastName: String, var age: Int)

48

Typical Scala!

Tuesday, July 20, 2010 Scala is much more succinct. It eliminates a lot of boilerplate.
slide-49
SLIDE 49

class Person( var firstName: String, var lastName: String, var age: Int) Class body is the “primary” constructor Parameter list for c’tor Makes the arg a field with accessors No class body {…}. nothing else needed!

49

Tuesday, July 20, 2010 Scala is much more succinct. It eliminates a lot of boilerplate.
slide-50
SLIDE 50

Actually, not exactly the same:

50

val person = new Person(“dean”,…) val fn = person.firstName person.firstName = “Bubba” // Not: // val fn = person.getFirstName // person.setFirstName(“Bubba”) Doesn’t follow the JavaBean convention.

Tuesday, July 20, 2010 Note that Scala does not define an argument list for “firstName”, so you can call this method as if it were a bare field access. The client doesnʼt need to know the difference!
slide-51
SLIDE 51

However, these are function calls:

51

class Person(fn: String, …) { // init val private var _firstName = fn def firstName = _firstName def firstName_=(fn: String) = _firstName = fn } Uniform Access Principle

Tuesday, July 20, 2010 Note that Scala does not define an argument list for “firstName”, so you can call this method as if it were a bare field access. The client doesnʼt need to know the difference!
slide-52
SLIDE 52

Scala’s Object Model: Traits

52

Composable Units of Behavior

Tuesday, July 20, 2010 Fixes limitations of Javaʼs object model.
slide-53
SLIDE 53

Java

class Queue extends Collection implements Logging, Filtering { … }

53

Tuesday, July 20, 2010 Made-up example Java type.
slide-54
SLIDE 54

Java’s object model

  • Good
  • Promotes abstractions.
  • Bad
  • No composition through

reusable mixins.

54

Tuesday, July 20, 2010 Chances are, the “logging” and “filtering” behaviors are reusable, yet Java provides no built-in way to “mix-in” reusable implementations. Ad hoc mechanisms must be used.
slide-55
SLIDE 55

Like interfaces with implementations,

55

Traits

Tuesday, July 20, 2010 One way to compare traits to what you know...
slide-56
SLIDE 56

… or like abstract classes + multiple inheritance (if you prefer).

56

Traits

Tuesday, July 20, 2010 … and another way.
slide-57
SLIDE 57

Example

trait Queue[T] { def get(): T def put(t: T) } A pure abstraction (in this case...)

57

Tuesday, July 20, 2010
slide-58
SLIDE 58

Log put and get

trait QueueLogging[T] extends Queue[T] { abstract override def put(t: T) = { println("put("+t+")") super.put(t) } abstract override def get() { … } }

58

Tuesday, July 20, 2010 (“get” is similar.) “Super” is not yet bound, because the “super.put(t)” so far could only call the abstract method in Logging, which is not allowed. Therefore, “super” will be bound “later”, as weʼll so. So, this method is STILL abstract and itʼs going to override a concrete “put” “real soon now”.
slide-59
SLIDE 59

trait QueueLogging[T] extends Queue[T] { abstract override def put(t: T) = { println("put("+t+")") super.put(t) } abstract override def get() { … } }

Log put and get

What is “super” bound to??

59

Tuesday, July 20, 2010 (Weʼre ignoring “get”…) “Super” is not yet bound, because the “super.put(t)” so far could only call the abstract method in Logging, which is not allowed. Therefore, “super” will be bound “later”, as weʼll so. So, this method is STILL abstract and itʼs going to override a concrete “put” “real soon now”.
slide-60
SLIDE 60

class StandardQueue[T] extends Queue[T] { import ...ArrayBuffer private val ab = new ArrayBuffer[T] def put(t: T) = ab += t def get() = ab.remove(0) … } Concrete (boring) implementation

60

Tuesday, July 20, 2010 Our concrete class. We import scala.collection.mutable.ArrayBuffer wherever we want, in this case, right were itʼs used. This is boring; itʼs just a vehicle for the cool traits stuff...
slide-61
SLIDE 61

val sq = new StandardQueue[Int] with QueueLogging[Int] sq.put(10) // #1 sq.get() // #2 // => put(10) (on #1) // => get(10) (on #2) Example use

61

Tuesday, July 20, 2010 We instantiate StandardQueue AND mixin the trait. We could also declare a class that mixes in the trait. The “put(10)” output comes from QueueLogging.put. So “super” is StandardQueue.
slide-62
SLIDE 62

Mixin composition; no class required

62

Example use val sq = new StandardQueue[Int] with QueueLogging[Int] sq.put(10) // #1 sq.get() // #2 // => put(10) (on #1) // => get(10) (on #2)

Tuesday, July 20, 2010 We instantiate StandardQueue AND mixin the trait. We could also declare a class that mixes in the trait. The “put(10)” output comes from QueueLogging.put. So “super” is StandardQueue.
slide-63
SLIDE 63

Traits give us advice, but not a join point “query” language.

63

Like Aspect-Oriented Programming?

Tuesday, July 20, 2010 If you know AspectJ or Spring AOP, traits make it easy to implement “advice”, but there is no join point language for querying over the set of all possible join points, like a real AOP framework provides.
slide-64
SLIDE 64

Stackable Traits

64

Tuesday, July 20, 2010
slide-65
SLIDE 65

Filter put

trait QueueFiltering[T] extends Queue[T] { abstract override def put( t: T) = { if (veto(t)) println(t+" rejected!") else super.put(t) } def veto(t: T): Boolean }

65

Tuesday, July 20, 2010 Like QueueLogging, this trait can veto potential puts. Implementers/subclasses decide what “veto” means.
slide-66
SLIDE 66

Filter put

trait QueueFiltering[T] extends Queue[T] { abstract override def put( t: T) = { if (veto(t)) println(t+" rejected!") else super.put(t) } def veto(t: T): Boolean }

66

“Veto” puts

Tuesday, July 20, 2010 Unlike QueueLogging, this trait can veto potential puts. Implementers/subclasses decide what “veto” means.
slide-67
SLIDE 67

val sq = new StandardQueue[Int] with QueueLogging[Int] with QueueFiltering[Int] { def veto(t: Int) = t < 0 } Defines “veto”

67

Anonymous Class

Tuesday, July 20, 2010 We instantiate StandardQueue AND mixin both traits. Note that we have to define veto for our current needs, in this case to prevent putting negative integers.
slide-68
SLIDE 68

for (i <- -2 to 2) { sq.put(i) } println(sq) // => -2 rejected! // => -1 rejected! // => put(0) // => put(1) // => put(2) // => 0, 1, 2 loop from -2 to 2

68

Filtering occurred before logging Example use

Tuesday, July 20, 2010 The filter traitʼs “put” is invoked before the logging traitʼs put.
slide-69
SLIDE 69

What if we reverse the order

  • f the Traits?

69

Tuesday, July 20, 2010
slide-70
SLIDE 70

val sq = new StandardQueue[Int] with QueueFiltering[Int] with QueueLogging[Int] { def veto(t: Int) = t < 0 } Order switched

70

Tuesday, July 20, 2010
slide-71
SLIDE 71

for (i <- -2 to 2) { sq.put(i) } println(sq) // => put(-2) // => -2 rejected! // => put(-1) // => -1 rejected! // => put(0) // => put(1) // => put(2) // => 0, 1, 2 logging comes before filtering!

71

Tuesday, July 20, 2010 Now, the logger traitʼs “put” is invoked before the filtering traitʼs put.
slide-72
SLIDE 72

Loosely speaking, the precedence goes right to left.

72“Linearization” algorithm

Tuesday, July 20, 2010 Method lookup algorithm is called “linearization”. For complex object graphs, it's a bit more complicated than "right to left".
slide-73
SLIDE 73

Method Lookup Order

  • Defined in object’s type?
  • Defined in mixed-in traits,

right to left?

  • Defined in superclass?

73 Simpler cases, only...

Tuesday, July 20, 2010 Can be more complex for complex hierarchies (but not that much more complex…). “Defined” also included “overridden”.
slide-74
SLIDE 74

Traits are also powerful for mixin composition.

74

Tuesday, July 20, 2010
slide-75
SLIDE 75

val dean = new Person(…) extends Logger dean.log(ERROR, “Bozo alert!!”)

75

trait Logger { def log(level: Level, message: String) = { Log.log(level, message) } }

Logger, revisited:

mixed in Logging

Tuesday, July 20, 2010 I changed some details compared to our original Logger example, e.g., no “level” field. Mix in Logger.
slide-76
SLIDE 76

DSLs

76

Yet more features for DSL creation...

Tuesday, July 20, 2010 Fixes limitations of Javaʼs object model.
slide-77
SLIDE 77

Building Our Own Controls

77

Exploiting First-Class Functions

Tuesday, July 20, 2010
slide-78
SLIDE 78

also the same as 1 + 2 // => 3 1.+(2) // => 3

Recall infix operator notation:

Why is this useful?? 1 + {2}

78

Tuesday, July 20, 2010 Syntactic sugar: obj.operation(arg) == obj operation arg
slide-79
SLIDE 79

// Print with line numbers. loop (new File("…")) { (n, line) => printf("%3d: %s\n", n, line) }

Make your own controls

79

Tuesday, July 20, 2010 If I put the “(n, line) =>” on the same line as the “{“, it would look like a Ruby block.
slide-80
SLIDE 80

// Print with line numbers. loop (new File("…")) { (n, line) => printf("%3d: %s\n", n, line) }

Make your own controls

control? How do we do this? File to loop through what do for each line Arguments passed to...

80

Tuesday, July 20, 2010
slide-81
SLIDE 81

1: // Print with line … 2: 3: 4: loop(new File("…")) { 5: (n, line) => 6: 7: printf("%3d: %s\n", … 8: }

Output on itself:

81

Tuesday, July 20, 2010
slide-82
SLIDE 82

import java.io._

  • bject Loop {

def loop(file: File, f: (Int,String) => Unit) = {…} }

82

Tuesday, July 20, 2010 Hereʼs the code that implements loop...
slide-83
SLIDE 83

import java.io._

  • bject Loop {

def loop(file: File, f: (Int,String) => Unit) = {…} } _ like * in Java “singleton” class == 1 object loop “control” function taking line # and line two parameters like “void”

83

Tuesday, July 20, 2010 Singleton “objects” replace Java statics (or Ruby class methods and attributes). As written, “loop” takes two parameters, the file to “numberate” and a the function that takes the line number and the corresponding line, does something, and returns Unit. Userʼs specify what to do through “f”.
slide-84
SLIDE 84
  • bject Loop {

def loop(file: File, f: (Int,String) => Unit) = {…} } two parameters

84

loop (new File("…")) { (n, line) => … }

Tuesday, July 20, 2010 The oval highlights the comma separating the two parameters in the list. Watch what we do on the next slide...
slide-85
SLIDE 85
  • bject Loop {

def loop(file: File) ( f: (Int,String) => Unit) = {…} } two parameters lists

85

loop (new File("…")) { (n, line) => … }

Tuesday, July 20, 2010 We convert the single, two parameter list to two, single parameter lists, which is valid syntax.
slide-86
SLIDE 86

// Print with line numbers. import Loop.loop loop (new File("…")) { (n, line) => printf("%3d: %s\n", n, line) }

Why 2 Param. Lists?

2nd parameter: a “function literal” import new method 1st param.: a file

86

Tuesday, July 20, 2010 Having two, single-item parameter lists, rather than one, two-item list, is necessary to allow the syntax shown here. The first parameter list is (file), while the second is {function literal}. Note that we have to import the loop method (like a static import in Java). Otherwise, we could write Loop.loop.
slide-87
SLIDE 87
  • bject Loop {

def loop(file: File) ( f: (Int,String) => Unit) = { val reader = new BufferedReader( new FileReader(file)) def doLoop(n:Int) = {…} doLoop(1) } } Finishing Loop.loop...

87

nested method

Tuesday, July 20, 2010 Finishing the implementation, loop creates a buffered reader, then calls a recursive, nested method "doLoop".
slide-88
SLIDE 88
  • bject Loop {

… def doLoop(n: Int):Unit ={ val l = reader.readLine() if (l != null) { f(n, l) doLoop(n+1) } } }

88

Finishing Loop.loop... “f” and “reader” visible from outer scope recursive

Tuesday, July 20, 2010 Here is the nested method, doLoop.
slide-89
SLIDE 89

doLoop is Recursive. There is no mutable loop counter!

Classic Functional Programming technique

89

Tuesday, July 20, 2010
slide-90
SLIDE 90

def doLoop(n: Int):Unit ={ … doLoop(n+1) }

90

Scala optimizes tail recursion into loops

It is Tail Recursive

Tuesday, July 20, 2010 A tail recursion - the recursive call is the last thing done in the function (or branch).
slide-91
SLIDE 91

// Print with line numbers. import Loop.loop loop (new File("…")) { (n, line) => printf("%3d: %s\n", n, line) }

Recap: Make a DSL

91

Tuesday, July 20, 2010 Weʼve used some syntactic sugar (infix operator notation, substituting {…} for (…)) and higher-order functions to build a tiny DSL. Other features supporting DSLs include implicits
slide-92
SLIDE 92

More Functional Hotness

92

Tuesday, July 20, 2010 FP is going mainstream because it is the best way to write robust concurrent software. Hereʼs an example...
slide-93
SLIDE 93

abstract class Option[T] {…} case class Some[T](t: T) extends Option[T] {…} case object None extends Option[Nothing] {…}

Avoiding Nulls

93

Child of all other types

Tuesday, July 20, 2010 I am omitting MANY details. You canʼt instantiate Option, which is an abstraction for a container/collection with 0 or 1 item. If you have one, it is in a Some, which must be a class, since it has an instance field, the item. However, None, used when there are 0 items, can be a singleton object, because it has no state! Note that type parameter for the parent Option. In the type system, Nothing is a subclass of all other types, so it substitutes for instances of all other types. This combined with a proper called covariant subtyping means that you could write “val x: Option[String = None” it would type correctly, as None (and Option[Nothing]) is a subtype of Option[String].
slide-94
SLIDE 94

case class Some[T](t: T)

Case Classes

94

Provides factory, pattern matching, equals, toString, and other goodies.

Tuesday, July 20, 2010 I am omitting MANY details. You canʼt instantiate Option, which is an abstraction for a container/collection with 0 or 1 item. If you have one, it is in a Some, which must be a class, since it has an instance field, the item. However, None, used when there are 0 items, can be a singleton object, because it has no state! Note that type parameter for the parent Option. In the type system, Nothing is a subclass of all other types, so it substitutes for instances of all other types. This combined with a proper called covariant subtyping means that you could write “val x: Option[String = None” it would type correctly, as None (and Option[Nothing]) is a subtype of Option[String].
slide-95
SLIDE 95

class Map1[K, V] { def get(key: K): V = { return v; // if found return null; // if not found } } class Map2[K, V] { def get(key: K): Option[V] = { return Some(v); // if found return None; // if not found } }

95

Which is the better API?

Tuesday, July 20, 2010 Returning Option tells the user that “there may not be a value” and forces proper handling, thereby drastically reducing sloppy code leading to NullPointerExceptions.
slide-96
SLIDE 96

val l = List( Some(“a”), None, Some(“b”), None, Some(“c”)) for (Some(s) <- l) yield s // List(a, b, c)

96

No “if” statement Pattern match; only take elements of “l” that are Somes.

For “Comprehensions”

Tuesday, July 20, 2010 Weʼre using the type system and pattern matching built into case classes to discriminate elements in the list. No conditional statements required. This is just the tip of the iceberg of what “for comprehensions” can do and not only with Options, but other containers, too.
slide-97
SLIDE 97

Actor Concurrency

97

Tuesday, July 20, 2010 FP is going mainstream because it is the best way to write robust concurrent software. Hereʼs an example...
slide-98
SLIDE 98

When you share mutable state...

Hic sunt dracones (Here be dragons)

98

Hard!

Tuesday, July 20, 2010 Itʼs very hard to do multithreaded programming robustly. We need higher levels of abstraction, like Actors.
slide-99
SLIDE 99

Actor Model

  • Message passing between

autonomous actors.

  • No shared (mutable) state.

99

Tuesday, July 20, 2010
slide-100
SLIDE 100

Actor Model

  • First developed in the 70’s by

Hewitt, Agha, Hoare, etc.

  • Made “famous” by Erlang.
  • Scala’s Actors patterned

after Erlang’s.

100

Tuesday, July 20, 2010

The actor model is not new!!

slide-101
SLIDE 101

“self” Display

draw draw ??? error! exit “exit”

2 Actors:

101

Tuesday, July 20, 2010 Our example
slide-102
SLIDE 102

package shapes case class Point( x: Double, y: Double) abstract class Shape { def draw() } Hierarchy of geometric shapes

Tuesday, July 20, 2010 “Case” classes for 2-dim. points and a hierarchy of shapes. Note the abstract draw method in Shape. The “case” keyword makes the arguments “vals” by default, adds factory, equals, etc.
  • methods. Great for “structural” objects.
(Case classes automatically get generated equals, hashCode, toString, so-called “apply” factory methods - so you donʼt need “new” - and so-called “unapply” methods used for pattern matching.)
slide-103
SLIDE 103

package shapes case class Point( x: Double, y: Double) abstract class Shape { def draw() } abstract “draw” method Hierarchy of geometric shapes

103

Tuesday, July 20, 2010 “Case” classes for 2-dim. points and a hierarchy of shapes. Note the abstract draw method in Shape. The “case” keyword makes the arguments “vals” by default, adds factory, equals, etc.
  • methods. Great for “structural” objects.
(Case classes automatically get generated equals, hashCode, toString, so-called “apply” factory methods - so you donʼt need “new” - and so-called “unapply” methods used for pattern matching.)
slide-104
SLIDE 104

case class Circle( center:Point, radius:Double) extends Shape { def draw() = … } case class Rectangle( ll:Point, h:Double, w:Double) extends Shape { def draw() = … } concrete “draw” methods Hierarchy of geometric shapes

104

Tuesday, July 20, 2010 Case classes for 2-dim. points and a hierarchy of shapes. Note the abstract draw method in Shape. For our example, the draw methods will just do “println(this.toString)”.
slide-105
SLIDE 105

package shapes import scala.actors._, Actor._

  • bject ShapeDrawingActor

extends Actor { def act() { loop { receive { … } } } } Actor for drawing shapes

105

Tuesday, July 20, 2010 An actor that waits for messages containing shapes to draw. Imagine this is the window manager on your computer. It loops indefinitely, blocking until a new message is received...
slide-106
SLIDE 106

package shapes import scala.actors._, Actor._

  • bject ShapeDrawingActor

extends Actor { def act() { loop { receive { … } } } } Actor library “singleton” Actor loop indefinitely receive and handle each message

106

Actor for drawing shapes

Tuesday, July 20, 2010 An actor that waits for messages containing shapes to draw. Imagine this is the window manager on your computer. It loops indefinitely, blocking until a new message is received...
slide-107
SLIDE 107

receive { case s:Shape => s.draw() sender ! "drawn" case "exit" => println("exiting...") sender ! "bye!" // exit case x => println("Error: " + x) sender ! ("Unknown: " + x) }

107

Receive method

Tuesday, July 20, 2010 “Receive” blocks until a message is received. Then it does a pattern match on the message. In this case, looking for a Shape object, the “exit” message, or an unexpected object, handled with the last case, the default.
slide-108
SLIDE 108

receive { case s:Shape => s.draw() sender ! "drawn" case "exit" => println("exiting...") sender ! "bye!" // exit case x => println("Error: " + x) sender ! ("Unknown: " + x) }

108

pattern matching

Tuesday, July 20, 2010 Each pattern is tested and the first match “wins”. The messages we expect are a Shape object, the “exit” string or anything else. Hence, the last “case” is a “default” that catches anything.
slide-109
SLIDE 109

receive { case s:Shape => s.draw() sender ! "drawn" case "exit" => println("exiting...") sender ! "bye!" // exit case x => println("Error: " + x) sender ! ("Unknown: " + x) } done unrecognized message draw shape & send reply

109

Tuesday, July 20, 2010 After handling each message, a response is sent to the sender, which we get by calling the “sender” method. The “!” is the message send method (from Erlang).
slide-110
SLIDE 110

package shapes import …

  • bject ShapeDrawingActor extends Actor {

def act() { loop { receive { case s: Shape => s.draw() sender ! "drawn" case "exit" => println("exiting...") sender ! "bye!" //; exit case x => println("Error: " + x) sender ! ("Unknown: " + x) } } } }

Altogether

110

Tuesday, July 20, 2010 The whole thing, with “elided” imports and other edits, so it would fit.
slide-111
SLIDE 111

import shapes._ import scala.actors.Actor._ def sendAndReceive(msg: Any) ={ ShapeDrawingActor ! msg self.receive { case reply => println(reply) } } script to try it out

111

Tuesday, July 20, 2010 Hereʼs a scala script (precompilation not required) to drive the drawing actor. Normally, you would not do such synchronous call and response coding...
slide-112
SLIDE 112

import shapes._ import scala.actors.Actor._ def sendAndReceive(msg: Any) ={ ShapeDrawingActor ! msg self.receive { case reply => println(reply) } } wait for a reply send message...

112

script to try it out helper method parent of AnyRef, AnyVal

Tuesday, July 20, 2010 The “!” method sends a message. Then we wait for a reply. In our receive method, we match on any “reply” and just print it. This script uses the method “self” to get the actor corresponding to “me”.
slide-113
SLIDE 113

… ShapeDrawingActor.start() sendAndReceive( Circle(Point(0.0,0.0), 1.0)) sendAndReceive( Rectangle(Point(0.0,0.0), 2, 5)) sendAndReceive(3.14159) sendAndReceive("exit") // => Circle(Point(0.0,0.0),1.0) // => drawn. // => Rectangle(Point(0.0,0.0),2.0,5.0) // => drawn. // => Error: 3.14159 // => Unknown message: 3.14159 // => exiting... // => bye!

113

Tuesday, July 20, 2010 Start the drawing actor, then send it four messages. The blue shows what gets printed (after the “// => “).
slide-114
SLIDE 114

… ShapeDrawingActor.start() sendAndReceive( Circle(Point(0.0,0.0), 1.0)) sendAndReceive( Rectangle(Point(0.0,0.0), 2, 5)) sendAndReceive(3.14159) sendAndReceive("exit") // => Circle(Point(0.0,0.0),1.0) // => drawn. // => Rectangle(Point(0.0,0.0),2.0,5.0) // => drawn. // => Error: 3.14159 // => Unknown message: 3.14159 // => exiting... // => bye!

114

Tuesday, July 20, 2010
slide-115
SLIDE 115

… receive { case s:Shape => s.draw() sender ! "drawn" case … case … } Functional style pattern matching A powerful combination! Object-

  • riented

polymorphism

115

Tuesday, July 20, 2010 The power of combining the best features of FP and OOP.
slide-116
SLIDE 116

Recap

116

Tuesday, July 20, 2010
slide-117
SLIDE 117

Scala is...

117

Tuesday, July 20, 2010
slide-118
SLIDE 118

a better Java and C#,

118

Tuesday, July 20, 2010
slide-119
SLIDE 119
  • bject-oriented

and functional,

119

Tuesday, July 20, 2010
slide-120
SLIDE 120

succinct, elegant, and powerful.

120

Tuesday, July 20, 2010
slide-121
SLIDE 121

Thanks!

dean@deanwampler.com @deanwampler polyglotprogramming.com/talks programmingscala.com

121

Tuesday, July 20, 2010
slide-122
SLIDE 122

Extra Slides

122

Tuesday, July 20, 2010
slide-123
SLIDE 123

Functional Programming

123

Tuesday, July 20, 2010
slide-124
SLIDE 124

What is Functional Programming?

Don’t we already write “functions”?

124

Tuesday, July 20, 2010
slide-125
SLIDE 125

y = sin(x)

125

Based on Mathematics

Tuesday, July 20, 2010

“Functional Programming” is based on the behavior of mathematical functions and variables.

slide-126
SLIDE 126

y = sin(x)

Setting x fixes y ∴ variables are immutable

126

Tuesday, July 20, 2010

“Functional Programming” is based on the behavior of mathematical functions. “Variables” are actually immutable values.

slide-127
SLIDE 127

20 += 1 ??

We never modify the 20 “object”

127

Tuesday, July 20, 2010
slide-128
SLIDE 128

No mutable state ∴ nothing to synchronize

Concurrency

128

Tuesday, July 20, 2010

FP is breaking out of the academic world, because it ofgers a better way to approach concurrency, which is becoming ubiquitous.

slide-129
SLIDE 129

When you share mutable state...

Hic sunt dracones (Here be dragons)

129

Tuesday, July 20, 2010
slide-130
SLIDE 130

y = sin(x)

Functions don’t change state ∴ side-effect free

130

Tuesday, July 20, 2010

A math function doesn’t change any “object” or global state. All the work it does is returned by the function. This property is called “referential transparency”.

slide-131
SLIDE 131

Side-effect free functions

  • Easy to reason about behavior.
  • Easy to invoke concurrently.
  • Easy to invoke anywhere.
  • Encourage immutable objects.

131

Tuesday, July 20, 2010 side-effect free functions are far less likely to introduce subtle integration bugs, especially in concurrent systems. By encouraging immutable objects (e.g., when methods return new objects, rather than modify existing ones), that improves concurrency robustness.
slide-132
SLIDE 132

tan(Θ) = sin(Θ)/cos(Θ) Compose functions of

  • ther functions

∴ first-class citizens

132

Tuesday, July 20, 2010 Function are “first-class citizens”; you can assign them to variables and pass them to other (higher-order) functions, giving you composable behavior.
slide-133
SLIDE 133

More on DSLs

133

Yet more features for DSL creation...

Tuesday, July 20, 2010 Fixes limitations of Javaʼs object model.
slide-134
SLIDE 134

“Pimp My Library”

134

Typesafe “monkey patching”

Tuesday, July 20, 2010 A funny name for a powerful feature, simulating open types (i.e., adding behavior to types) in a type-safe way.
slide-135
SLIDE 135

// Print with line numbers. import Loop.loop loop (new File("…")) { (n, line) => printf("%3d: %s\n", n, line) }

Recall our “Loop”

135

Tuesday, July 20, 2010 We defined this earlier.
slide-136
SLIDE 136

Suppose we want a loop method on File instead?

136

Tuesday, July 20, 2010
slide-137
SLIDE 137

val file = new File("…") file.loop { (n, line) => printf("%3d: %s\n", n, line) }

137

Now a method

  • n File?
Tuesday, July 20, 2010 What if we would prefer for File to have a loop method instead? Is this possible in Scala?
slide-138
SLIDE 138

class File; …; end file = File.new … def file.loop n = 0 while line = self.gets yield n, line n += 1 end end

Ruby

138

Open Types Add a method to the object!

Tuesday, July 20, 2010 In languages with open types, like Ruby, we can easily add new methods to types or individual objects. Canʼt do that in Scala, right?
slide-139
SLIDE 139

Implicits

139

class WithLoop (file: File) { def loop ( f: (Int,String) => Unit) = {…} }

  • bject WithLoop {

implicit def file2WithLoop( file: File) = new WithLoop (file) }

Tuesday, July 20, 2010 You canʼt do that in Scala, but “implicits” let you define a conversion from the type you have to a new type that has the method you want. The syntax you use looks as if you have the method
  • n the original type. The compiler finds the best-matching implicit conversion method in scope and applies it for you.
The implicit function will be used by the compiler to convert a File to a WithLoop, then we can call the loop method, which now has only one argument, the function to apply to each line in the file. Technical note. Because of closures, we donʼt actually need to make the File a field (val) of the class. Also, itʼs okay for the object and class to have the same names; they are called “companions”.
slide-140
SLIDE 140

// Print with line numbers. import WithLoop._ (new File("…")).loop { (n, line) => printf("%3d: %s\n", n, line) }

Using the Implicit

140

import required!

Tuesday, July 20, 2010 The compiler sees you try to call loop() on a File object, but that method doesnʼt exist. So, it looks for another type that has the loop method and an implicit conversion method in scope to convert from File to the other type. It then calls loop on the new object.
slide-141
SLIDE 141

Implicits can be used to mimic Haskell-like type classes.

141

http://debasishg.blogspot.com/2010/06/ scala-implicits-type-classes-here-i.html

Tuesday, July 20, 2010