Multiparadigm Programming in Scala

Download Report

Transcript Multiparadigm Programming in Scala

Multiparadigm Programming
in Scala
Adapted from presentation by
H. C. Cunningham and J. C. Church
University of Mississipi
What is Multiparadigm
Programming?
Definition:
A multiparadigm programming language provides “ a
framework in which programmers can work in a variety
of styles, freely intermixing constructs from different
paradigms.” [Tim Budd]
Programming paradigms:


imperative versus declarative (e.g., functional, logic)
other dimensions – object-oriented, component-oriented,
concurrency-oriented, etc.
CS3180 (Prasad)
ScalaMulti
2
Why Learn Multiparadigm
Programming?
Tim Budd:
“Research results from the psychology of programming
indicate that expertise in programming is far more
strongly related to the number of different
programming styles understood by an individual than it
is the number of years of experience in programming.”
The “goal of multiparadigm computing is to provide ...
a number of different problem-solving styles” so that a
programmer can “select a solution technique that best
matches the characteristics of the problem”.
CS3180 (Prasad)
ScalaMulti
3
Why Teach Multiparadigm
Programming?

Contemporary
imperative
and
object-oriented
languages increasingly have functional programming
features, e.g.,
•
•

higher order functions (closures)
list comprehensions
New
explicitly
multiparadigm
(objectoriented/functional) languages are appearing, e.g.,
•
•
Scala on the Java platform (and .Net in future)
F# on the .Net platform
CS3180 (Prasad)
ScalaMulti
4
Scala
Programming language developed by Martin Odersky’s team at
EPFL in Switzerland
 Executes on the Java platform
 Integrates with Java
 Has growing usage (e.g., Twitter, Foursquare, and Linkedin)
Multiparadigm language
 Object-oriented (with generics and mixins)
 Functional (similar to Haskell and SML)
 Extensible (method calls as operators, currying, closures, byname parameters)
•
•

Actor-based concurrency-oriented programming
Language-oriented programming
Statically typed with Hindley-Milner type inference
CS3180 (Prasad)
ScalaMulti
5
Why Scala?
(Coming from Java/C++)




Runs on the JVM
 Can use any Java code in Scala
 Almost as fast as Java (within 10%)
Much shorter code
 Odersky reports 50% reduction in most code over Java
 Local type inference
Fewer errors
 No Null Pointer problems
More flexibility
 As many public classes per source file as you want
 Operator overloading
6
Scala References

Website http://www.scala-lang.org
•
•
Martin Odersky. Scala Tutorial for Java Programmers.
Martin Odersky. Scala By Example.

Martin Odersky, Lex Spoon, and Bill Venners.
Programming in Scala: A Comprehensive Step-By-Step
Guide, 2nd Edition, Artima, Inc., 2010.

Books on Scala:
http://www.scala-lang.org/node/959
CS3180 (Prasad)
ScalaMulti
7
Scala object system




Class-based
Single inheritance
Can define singleton objects easily (no need
for static which is not really OO)
Traits, compound types, and views allow for
more flexibility
8
Basic Scala

Use var to declare variables:
var x = 3;
x += 4;

Use val to declare values (final vars)
val y = 3;
y += 4; // error

Notice no types, but it is statically typed
var x = 3;
x = “hello world”; // error

Type annotations:
var x : Int = 3;
9
Functional Scala

Defining lambdas – nameless functions
val f = x :Int => x + 42;
f : mapping :int ->
int

Closures! A way to haul around state
var y = 3;
val g = {x : Int => y += 1; x+y; }

Maps (and a cool way to do some functions)
List(1,2,3).map(_+10).foreach(println)

Filtering (and ranges!)
1 to 100 filter (_ % 7 == 3) foreach (println)

(Feels a bit like UNIX pipes?)
10
Defining Hello World
object HelloWorld {
def main(args: Array[String]){
println("Hey world!")
}
}
 Singleton object named HelloWorld (also replaces
static methods and variables)
 Method main defined (procedure)
 Parameter args of type Array[String]
 Array is generic class with type parameter
CS3180 (Prasad)
ScalaMulti
11
Interpreting Hello World
> scala
This is a Scala shell.
Type in expressions to have them evaluated.
Type :help for more information.
scala> object HelloWorld {
| def main(args: Array[String]) {
|
println("Hey world!")
| }
|}
defined module HelloWorld
scala> HelloWorld.main(null)
Hey world!
unnamed0: Unit = ()
scala>:q
CS3180 (Prasad)
ScalaMulti
12
Compiling & Executing Hello World
> scalac HelloWorld.scala
> scala HelloWorld
Hey world!
CS3180 (Prasad)
ScalaMulti
13
Numbers are Objects

Consider expression
1 + 2 * 3 / x

Operators are method calls (like Smalltalk)

Operator symbols are identifiers

Expression above is same as
(1).+(((2).*(3))./(x))
CS3180 (Prasad)
ScalaMulti
14
Functions are Objects
object Timer {
def oncePerSecond(callback:() => Unit){
while (true) {
callback(); Thread sleep 1000
} // 1-arg method sleep used as operator
}
def welcome() {
println("Welcome to CS3180!")
}
def main(args: Array[String]) {
oncePerSecond(welcome)
}
}
CS3180 (Prasad)
ScalaMulti
15
Timer Execution
scala> :l Timer.scala
Loading Timer.scala...
defined module Timer
scala> Timer.main(null)
Welcome to CS3180!
Welcome to CS3180!
Welcome to CS3180!
…
CS3180 (Prasad)
ScalaMulti
16
Anonymous Functions
object Timer {
def oncePerSecond(callback:() => Unit){
while (true) {
callback(); Thread sleep 1000
}
}
def main(args: Array[String]) {
oncePerSecond(
() => println("Welcome to CS3180!") )
}
}
CS3180 (Prasad)
ScalaMulti
17
Classes
class Complex(real: Double, imag: Double){
def re = real
def im = imag
}





Class primary constructor combined with class body
Parameters of class private constants within class
Parameterless methods re and im
Return types of re and im inferred from expression
(cannot be inferred for recursive functions)
Thus more concise syntax
CS3180 (Prasad)
ScalaMulti
18
Method Overriding
// Complex.scala
class Complex(real: Double, imag: Double) {
def re = real
def im = imag
override def toString =
re + (if (im < 0.0) "" else "+") +
im + ”I"
}



Classes extend class AnyRef by default
Methods must explicitly override parent method
if expressions
CS3180 (Prasad)
ScalaMulti
19
Using Classes and Objects
scala> :load Complex.scala
Loading Complex.scala...
defined class Complex
scala> val x = new Complex(1,-3)
x: Complex = 1.0-3.0i
scala> x.toString
res0: java.lang.String = 1.0-3.0i
CS3180 (Prasad)
ScalaMulti
20
Case Classes
abstract class Tree // Expression Trees
case class Sum(l: Tree, r: Tree)
extends Tree
case class Var(n: String) extends Tree
case class Const(v: int) extends Tree



Cf. Algebraic data types as in functional languages
Keyword new not needed to create instances (objects)
Getters defined automatically for constructor parameters


Pattern matching can be used to decompose
equals method defined on structure of instances
CS3180 (Prasad)
ScalaMulti
21
Pattern Matching
object Expressions {
type Environ = String => Int
def eval(t: Tree, env: Environ): Int = t match {
case Sum(l,r) => eval(l,env) + eval(r,env)
case Var(n)
=> env(n)
case Const(v) => v
}
def derive(t: Tree, v: String): Tree = t match {
case Sum(l,r)
=> Sum(derive(l,v),
derive(r,v))
case Var(n) if (v == n) => Const(1)
case _
=> Const(0)
}
CS3180 (Prasad)
ScalaMulti
22
Test Expression Trees
def main(args: Array[String]) {
val exp: Tree =
Sum(Sum(Var("x"),Var("x")),
Sum(Const(7),Var("y")))
val env: Environ =
{ case "x" => 5 case "y" => 7 }
println("Expression: " + exp)
println("Evaluation with x=5, y=7: " +
eval(exp,env))
println("Derivative relative to x:\n " +
derive(exp, "x"))
println("Derivative relative to y:\n " +
derive(exp, "y"))
}
}
CS3180 (Prasad)
ScalaMulti
23
Execute Expression Trees
scala> :load Expressions.scala
Loading Expressions.scala...
…
scala> Expressions.main(null)
Expression:
Sum(Sum(Var(x),Var(x)),Sum(Const(7),Var(y)))
Evaluation with x=5, y=7: 24
Derivative relative to x:
Sum(Sum(Const(1),Const(1)),Sum(Const(0),Const(0)))
Derivative relative to y:
Sum(Sum(Const(0),Const(0)),Sum(Const(0),Const(1)))
CS3180 (Prasad)
ScalaMulti
24
Defs, Vals, and Vars
Three types of identifier definitions:
def defines functions with parameters; RHS expression
evaluated each time called
val defines unchanging values; RHS expression
evaluated immediately to initialize
var defines storage location whose values can be
changed by assignment statements; RHS expression
evaluated immediately to initialize
CS3180 (Prasad)
ScalaMulti
25
Traits
trait Ord { // Order comparison operators
def < (that: Any): Boolean // abstract
def <=(that: Any): Boolean =
(this < that) || (this == that)
def > (that: Any): Boolean =
!(this <= that)
def >=(that: Any): Boolean =
!(this < that)
}
 Like Java interfaces except can have concrete methods
 Can be “mixed-in” to class
 Note that < is abstract; others defined with < and equals
CS3180 (Prasad)
ScalaMulti
26
Date Class with Mixin Trait Ord
class Date(y: Int, m: Int, d: Int)
extends Ord {
def year = y
def month = m
def day
= d
override def toString(): String =
year + "-" + month + "-" + day
// … need definition of < and equals
}


Can only extend one class or trait
May mix-in additional classes using keyword with
CS3180 (Prasad)
ScalaMulti
27
Date Class Equals Method
override def equals(that: Any): Boolean =
that.isInstanceOf[Date] && {
val o = that.asInstanceOf[Date]
o.day == day && o.month == month &&
o.year == year
}



isInstanceOf[T] checks whether object is an instance of
the given type T
asInstanceOf[T] casts static type to T if compatible
with dynamic type of object
Value of last statement of function is returned
CS3180 (Prasad)
ScalaMulti
28
Date Class < Method
def <(that: Any): Boolean = {
if (!that.isInstanceOf[Date])
error("Cannot compare " + that +
" and a Date")
val o = that.asInstanceOf[Date]
(year < o.year) ||
(year == o.year &&
(month < o.month ||
(month == o.month && day < o.day)))
}
CS3180 (Prasad)
ScalaMulti
29
DateTest
object DateTest {
def main(args: Array[String]) {
val x = new Date(1,1,2000)
val y = new Date(12,31,2001)
println("x = " + x)
println("y = " + y)
println("x < y: " + (x<y))
println("x > y: " + (x>y))
}
}
CS3180 (Prasad)
ScalaMulti
30
DateTest Output
>
x
y
x
x
scala DateTest
= 1-1-2000
= 12-31-2001
< y: true
> y: false
CS3180 (Prasad)
ScalaMulti
31
Scala Functions






Are first-class values – i.e., functions are objects
Can be higher-order – take functions as arguments or
return them as result
Can be anonymous
May be curried – take arguments one at a time, allowing
partial application
Are often passed in a closure – with references to free
variables they maninpulate
Provide ability to build powerful libraries of higherorder functions
CS3180 (Prasad)
ScalaMulti
32
Curried Functions
scala> def add(x: Int, y: Int) = x + y
add: (Int,Int)Int
scala> add(1,3)
res0: Int = 4
scala> def addc(x: Int)(y: Int) = x + y
addc: (Int)(Int)Int
scala> addc(1)(3)
res1: Int = 4
CS3180 (Prasad)
ScalaMulti
33
Partial Application
scala> def addc(x: Int)(y: Int) = x + y
addc: (Int)(Int)Int
scala> val z = addc(1) _
z: (Int) => Int = <function>
scala> z(3)
res2: Int = 4
CS3180 (Prasad)
ScalaMulti
34
Closures
scala> val inc = 10
inc: Int = 10
scala> def incre(x: Int) = x + inc
incre: (Int)Int
scala> def app(y: Int, g: (Int=>Int)) = g(y)
app: (Int,(Int) => Int)Int
scala> app(13,incre)
res0: Int = 23
CS3180 (Prasad)
ScalaMulti
35
Using List Map
scala> val xs = List(3,4,5)
xs: List[Int] = List(3, 4, 5)
scala> val triples = xs.map(x => 3*x)
triples: List[Int] = List(9, 12, 15)
scala> val evens = xs.filter(x => x%2==0)
evens: List[Int] = List(4)
CS3180 (Prasad)
ScalaMulti
37
Other Higher Order List Methods

flatMap

foldLeft, foldRight

reduceLeft, reduceRight

takeWhile, dropWhile

span, break

foreach
CS3180 (Prasad)
ScalaMulti
39
For Comprehensions
scala> for(i <- 1 to 30;
|
j <- List(2,3,5,7);
|
if i % j == 0) yield (i,j)

res0: scala.collection.immutable.IndexedSeq[(Int, Int)] =
Vector((2,2), (3,3), (4,2), (5,5), (6,2),
(6,3), (7,7), (8,2), (9,3), (10,2), (10,5),
(12,2), (12,3), (14,2), (14,7), (15,3), (15,5),
(16,2),(18,2), (18,3), (20,2), (20,5), (21,3),
(21,7), (22,2), (24,2), (24,3), (25,5), (26,2),
(27,3), (28,2), (28,7), (30,2), (30,3), (30,5))
CS3180 (Prasad)
ScalaMulti
40
Scala class hierarchy
Actors in Scala
CS3180 (Prasad)
ScalaMulti
43
Motivation



Concurrency is hard!
Real World is parallel and distributed.
Erlang's notion of a process:



Concurrent processes should pass messages to other
processes rather than share memory.
Erlang's processes are part of the language.
Scala's actors are part of the library.
CS3180 (Prasad)
ScalaMulti
44
Actors




Actors act independent of other actors.
Actors have mailboxes.
Actors communicate by sending messages to
other actors.
Actors will check their mailbox and react to their
messages.
CS3180 (Prasad)
ScalaMulti
45
Message in a Bottle

Any object can be sent to an Actor
case object myMessageObject
...
myActor ! myMessageObject
CS3180 (Prasad)
ScalaMulti
46
Please Mr. Postman

How urgent is it?
react: I need it now!
 receiveWithin: I need it soon!
 receive: I'll wait.


All three methods will perform pattern matching
on the objects received.
CS3180 (Prasad)
ScalaMulti
47
Overacting
import scala.actors._
object SillyActor extends Actor {
def act() { // Defines how our actor acts
for (i <- 1 to 5) {
println(“I'm acting!”)
Thread.sleep(1000)
}
}
}
...
SillyActor.start() // Begins acting
CS3180 (Prasad)
ScalaMulti
48
Vegetable Launcher
case object Tomato
case object Lettuce
object VegetableLauncher extends Actor {
def act() {
for (i <- 1 to 5) {
VegetableCatcher ! Tomato
// Send it!
Thread.sleep(1000)
VegetableCatcher ! Lettuce // Send it!
Thread.sleep(1000)
}
}
}
CS3180 (Prasad)
ScalaMulti
49
Vegetable Catcher
object VegetableCatcher extends Actor {
def act() {
loop {
react { // Non-blocking call
// Pattern Matching
case Lettuce =>
println("I caught a lettuce!")
case Tomato =>
println("I caught a tomato!")
}
}
}
}
CS3180 (Prasad)
ScalaMulti
50
Lights, Camera, ...
VegetableLauncher.start()
VegetableCatcher.start()
SillyActor.start()
I'm acting!
I caught a tomato!
I'm acting!
I caught a lettuce!
I'm acting!
I caught a tomato!
I'm acting!
I caught a lettuce!
I'm acting!
I caught a tomato!
I caught a lettuce!
I caught a tomato!
I caught a lettuce!
I caught a tomato!
I caught a lettuce!
CS3180 (Prasad)
ScalaMulti
51