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