Your SlideShare is downloading. ×
0
an introduction
Michel Schinz
What is Scala?
Scala is a programming language that:
• coherently combines the best aspects of
object-oriented and functio...
Object-oriented
programming in Scala
Rational numbers

First example: model rational numbers n / d where
n and d are integers, and d ≠ 0.
Provide addition, mul...
A class for rationals (1)
class Rational(n0: Int, d0: Int) {
require(d0 != 0)
constructor arguments
private def gcd(x: Int...
A class for rationals (2)
…continued
def +(that: Rational): Rational =
new Rational(this.n * that.d +
that.n * this.d,
pub...
Using rationals
scala> val r1 = new Rational(1, 3)
r1: Rational = 1/3 primary constructor call
inferred type

scala> val r...
A companion for rationals
singleton

companion object for class Rational

object Rational {
def apply(n: Int, d: Int): Rat...
Ordered objects
type parameter

trait Ordered[T] {
def compare(that: T): Int abstract method
def < (that: T): Boolean =
(t...
Ordered rationals
class Rational(n0: Int, d0: Int)
extends Ordered[Rational] {
… as before
provides <, <=, > and >= method...
Cells

Second example: model mutable cells that contain
a single value of some arbitrary type.
Additionally, define logging...
A class for generic cells
make init available as a field

class Cell[T](val init: T) {
private var v = init
mutable field

d...
A trait for logging cells
trait LoggingCell[T] extends Cell[T] {
override def get(): T = {
println("getting "+ this)
super...
A trait for undoable cells
trait UndoableCell[T] extends Cell[T] {
import collection.mutable.ArrayStack
private var hist =...
Mixin composition
new Cell(0)

basic integer cell

new Cell(0)
logging integer
with LoggingCell[Int]
cell
new Cell(0)
with...
The Scala library
Optional values
An optional value is either empty, or contains a
single element.
Example use: as a clean replacement for n...
Optional values (2)
can be matched (see later) & compiler-provided methods

case class Some[+T](x: T)
extends Option[T] {
...
Using optional values
compiler-provided factory method

scala> val v1 = Some("something")
v1: Some[String] = Some(somethin...
Tuples
A tuple of size n contains exactly n heterogenous
elements – i.e. they can be of different types.
Example use: a fu...
Short tuple syntax
Scala offers syntactic shortcuts for tuple values:
(e1, …, en) ≣ Tuplen(e1, …, en)
and for tuple types:...
(Im)mutable collections
Options and tuples are immutable.
Standard collections (sequences, sets, maps) are
provided in mut...
Immutable lists
An immutable list is either empty or composed of
a head element and a tail, which is another list.
abstrac...
Immutable lists (2)
case class ::[T](val head: T,
val tail: List[T])
extends List[T] {
def isEmpty = false
}
case object N...
Sequences, maps and sets
scala> val aSeq = Seq("zero","one","two")
scala> aSeq(1)
res1: String = one
scala> val aMap = Map...
For loops
For loops enable iteration over the elements of
collections, using a syntax that is reminiscent of
SQL queries.
...
Pattern matching
Pattern matching
Instances of case classes can easily be
constructed:
scala> Some((1,2))
res: Some[(Int,Int)] = Some((1,2)...
Integer division
def divMod(n: Int, d: Int):
Option[(Int,Int)] = {
if (d == 0)
None
else {
…compute quotient q and remaind...
Using integer division
def testDivMod(n: Int, d: Int) =
divMod(n, d) match {
case Some((q, r)) =>
println("quot: "+ q +" r...
Pattern matching lists
Since lists are recursive, it is natural to manipulate
them with recursive functions.
Furthermore, ...
Typed patterns
Pattern matching can also be used to discriminate
on the type of a value:
supertype of all types

def succA...
Exception handling
Unsurprisingly, exception handling is done using
pattern matching:
try {
val f = new FileInputStream("f...
Functional
programming in Scala
What is FP?
The functional style of programming is one that
relies on mathematical functions as the basic
building block o...
What is a FPL?
A functional programming language is one that
encourages the functional style of programming
by:
• offering...
Why is FP interesting?
Side-effects complicate several classes of
programs, like:
• concurrent programs with shared, mutab...
A trait for functions
trait Function1[F, T] { f =>
def apply(x: F): T
new name for this
def compose[F2](g: Function1[F2, F...
Using functions as values
scala> val succ = new Fun[Int,Int] {
def apply(x: Int) = x + 1 }
succ: …with Function1[Int,Int] ...
se
!

Using functions as values

W
or

ks

,b

ut

w
ay

to
o

ve
rb
o

scala> val succ = new Fun[Int,Int] {
def apply(x: ...
Functional syntactic sugar
anonymous function

scala> val succ = { x: Int => x + 1 }
succ: (Int) => Int = <function1>
a.k....
Partial application
Function values can also be created by applying
existing functions or methods to a (possibly empty)
su...
Collections as functions
Most collections are functions:
• Seq[T] has type Int=>T,
• Map[K,V] has type K=>V,
• Set[T] has ...
Operating on collections
Functional values are ideal to operate on
collections. Examples:
scala> val s = Seq(1,2,3,4,5)
sc...
Project Euler: problem 8
Solving problem 8
val n = "7316717653133062491922511967442…"
val digits = s.toList map (_.asDigit)
def prods(l: List[Int])...
For loops translation
The for notation is pure syntactic sugar. The
example:
for (user <- users
if (user.isMale
&& user.ag...
Implicits
Scala implicits
Scala offers two notions of implicit entities that are
automatically inserted by the compiler in certain
c...
Implicit conversions
An implicit conversion from Int to Rational
can be added to the latter’s companion object:
object Rat...
“Pimp my library”
Implicit conversions make it possible to
“augment” existing classes by implicitly wrapping
them – known ...
Implicit parameters
repeated parameter

def max[T](xs: T*)
(implicit ord: Ordering[T]): T =
xs reduceLeft ord.max
implicit...
Working with XML
data
XML literals
Scala supports XML literals, which are translated
to instances of various classes in scala.xml.
scala> val he...
XPath-like queries
scala> val users =
<users>
<user name="Roger" age="12"/>
<user name="Mary" age="44"/>
<user name="Jean"...
XML pattern matching
def parseRow(r: xml.Node): (String, Int) =
r match {
case <tr><td>{ name }</td>
<td>{ age }</td></tr>...
Testing with
ScalaCheck
Properties for rationals
The operations we defined on rationals should
satisfy several properties:
• ∀x, y ∈ Q: x + 0 = 0 +...
Properties for rationals
object RatProps extends Properties("Rat") {
property("+ left unit") =
Prop.forAll((x: Rational) =...
Generating rationals
ScalaCheck doesn’t know how to generate
arbitrary rationals, but we can easily define a
generator for ...
Testing rationals
%
+
+
+

scala
Rat.+
Rat.+
Rat.+

RatProps
left unit: OK, passed 100 tests.
right unit: OK, passed 100 t...
Further reading
http://www.scala-lang.org/
Two books about Scala:
• Programming in Scala by Odersky, Spoon &
Venners
• Pro...
Upcoming SlideShare
Loading in...5
×

Introduction à Scala - Michel Schinz - January 2010

443

Published on

Introduction à Scala - Michel Schinz - January 2010

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
443
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
8
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Transcript of "Introduction à Scala - Michel Schinz - January 2010"

  1. 1. an introduction Michel Schinz
  2. 2. What is Scala? Scala is a programming language that: • coherently combines the best aspects of object-oriented and functional programming languages, • runs on the JVM and is fully interopeable with Java – a .NET version is in the works, • is statically typed and very concise, • offers a high level of abstraction and good performances.
  3. 3. Object-oriented programming in Scala
  4. 4. Rational numbers First example: model rational numbers n / d where n and d are integers, and d ≠ 0. Provide addition, multiplication and comparison of rationals.
  5. 5. A class for rationals (1) class Rational(n0: Int, d0: Int) { require(d0 != 0) constructor arguments private def gcd(x: Int, y: Int): Int = if (y == 0) x else gcd(y, x % y) no return no explicit type (Int inferred) private val g = gcd(n0.abs, d0.abs) val n: Int = n0 / g public fields val d: Int = d0 / g (immutable) def this(n: Int) = this(n, 1) to be continued… auxiliary constructor
  6. 6. A class for rationals (2) …continued def +(that: Rational): Rational = new Rational(this.n * that.d + that.n * this.d, public this.d * that.d) method def *(that: Rational): Rational = new Rational(this.n * that.n, this.d * that.d) override def toString: String = n +"/"+ d } parameterless method
  7. 7. Using rationals scala> val r1 = new Rational(1, 3) r1: Rational = 1/3 primary constructor call inferred type scala> val r2 = new Rational(5) r2: Rational = 5/1 auxiliary constructor call scala> r1 + r2 // or: r1.+(r2) res0: Rational = 16/3 scala> res0 * r1 // or: res0.*(r1) res1: Rational = 16/9
  8. 8. A companion for rationals singleton companion object for class Rational object Rational { def apply(n: Int, d: Int): Rational = new Rational(n, d) def apply(n: Int): Rational = new Rational(n) val ZERO = new Rational(0) } implicitly calls apply scala> Rational(2,5) + Rational.ZERO res1: Rational = 2/5
  9. 9. Ordered objects type parameter trait Ordered[T] { def compare(that: T): Int abstract method def < (that: T): Boolean = (this compare that) < 0 def <=(that: T): Boolean = (this compare that) <= 0 def > (that: T): Boolean = (this compare that) > 0 def >=(that: T): Boolean = (this compare that) >= 0 }
  10. 10. Ordered rationals class Rational(n0: Int, d0: Int) extends Ordered[Rational] { … as before provides <, <=, > and >= methods def compare(that: Rational): Int = (n * that.d) compare (that.n * d) }
  11. 11. Cells Second example: model mutable cells that contain a single value of some arbitrary type. Additionally, define logging and undoable variants.
  12. 12. A class for generic cells make init available as a field class Cell[T](val init: T) { private var v = init mutable field def get(): T = v def set(v1: T): Unit = { v = v1 } ≈ Java’s void override def toString: String = "Cell("+ v +")" }
  13. 13. A trait for logging cells trait LoggingCell[T] extends Cell[T] { override def get(): T = { println("getting "+ this) super.get() } override def set(v1: T): Unit = { println("setting "+ this +" to "+ v1) super.set(v1) } }
  14. 14. A trait for undoable cells trait UndoableCell[T] extends Cell[T] { import collection.mutable.ArrayStack private var hist = new ArrayStack[T]() override def set(v1: T): Unit = { hist.push(super.get()) super.set(v1) } def undo(): Unit = super.set(hist pop) }
  15. 15. Mixin composition new Cell(0) basic integer cell new Cell(0) logging integer with LoggingCell[Int] cell new Cell(0) with LoggingCell[Int] logging, undoable with UndoableCell[Int] integer cell (undos are logged) new Cell(0) with UndoableCell[Int] with LoggingCell[Int] logging, undoable integer cell (undos are not logged)
  16. 16. The Scala library
  17. 17. Optional values An optional value is either empty, or contains a single element. Example use: as a clean replacement for null. variance (here co-variant) abstract class Option[+T] { def isEmpty: Boolean def get: T bounded type parameter def getOrElse[U >: T](d: =>U): U = if (isEmpty) d else get by-name parameter …many more methods }
  18. 18. Optional values (2) can be matched (see later) & compiler-provided methods case class Some[+T](x: T) extends Option[T] { def isEmpty = false def get = x } case object None subtype of all types extends Option[Nothing] { def isEmpty = true def get = throw new … }
  19. 19. Using optional values compiler-provided factory method scala> val v1 = Some("something") v1: Some[String] = Some(something) compiler-provided toString method scala> val v2 = None v2: None.type = None scala> v1 getOrElse "nothing" res1: String = something scala> v2 getOrElse "nothing" res2: String = nothing
  20. 20. Tuples A tuple of size n contains exactly n heterogenous elements – i.e. they can be of different types. Example use: a function that has to return n values can return them wrapped in a single tuple. case class Tuple2[+T1,+T2]( _1: T1, _2: T2) case class Tuple3[+T1,+T2,+T3]( _1: T1, _2: T2, _3: T3) etc.
  21. 21. Short tuple syntax Scala offers syntactic shortcuts for tuple values: (e1, …, en) ≣ Tuplen(e1, …, en) and for tuple types: (T1, …, Tn) ≣ Tuplen[T1, …, Tn] Example: scala> val p = ("Orwell", 1984) p: (String, Int) = (Orwell,1984) scala> p._1 arguments of case classes are fields res1: String = Orwell
  22. 22. (Im)mutable collections Options and tuples are immutable. Standard collections (sequences, sets, maps) are provided in mutable and immutable variants. Mutable collections are similar to the ones found in Java and other imperative languages. Immutable collections are similar to the ones found in typical functional languages.
  23. 23. Immutable lists An immutable list is either empty or composed of a head element and a tail, which is another list. abstract class List[+T] { def isEmpty: Boolean def head: T def tail: List[T] def ::[U >: T](x: U): List[U] = new ::[U](x, this) …many more methods }
  24. 24. Immutable lists (2) case class ::[T](val head: T, val tail: List[T]) extends List[T] { def isEmpty = false } case object Nil extends List[Nothing] { def isEmpty = true def head: Nothing = throw new … def tail: List[Nothing] = throw new … }
  25. 25. Sequences, maps and sets scala> val aSeq = Seq("zero","one","two") scala> aSeq(1) res1: String = one scala> val aMap = Map("zero" -> 0, "one" -> 1, "two" -> 2) scala> aMap("one") res2: Int = 1 scala> val aSet = Set("zero","one","two") scala> aSet("one") res3: Boolean = true
  26. 26. For loops For loops enable iteration over the elements of collections, using a syntax that is reminiscent of SQL queries. for (user <- users if (user.isMale && user.age > 30)) yield user.name
  27. 27. Pattern matching
  28. 28. Pattern matching Instances of case classes can easily be constructed: scala> Some((1,2)) res: Some[(Int,Int)] = Some((1,2)) Pattern matching makes deconstruction of case classes similarly easy.
  29. 29. Integer division def divMod(n: Int, d: Int): Option[(Int,Int)] = { if (d == 0) None else { …compute quotient q and remainder r Some((q, r)) } }
  30. 30. Using integer division def testDivMod(n: Int, d: Int) = divMod(n, d) match { case Some((q, r)) => println("quot: "+ q +" rem: "+ r) case None => println("<no result>") } scala> testDivMod(5, 3) quot: 1 rem: 2 scala> testDivMod(5, 0) <no result>
  31. 31. Pattern matching lists Since lists are recursive, it is natural to manipulate them with recursive functions. Furthermore, since they are defined as a disjunction of two cases (non-empty / empty list), it is natural to use pattern matching to do a case analysis. Example: a function to sum a list of integers. def sum(l: List[Int]): Int = l match { case h :: t => h + sum(t) case Nil => 0 }
  32. 32. Typed patterns Pattern matching can also be used to discriminate on the type of a value: supertype of all types def succAny(x: Any): Any = x match { case i: Int => i + 1 Int and Long are not case l: Long => l + 1 case classes case other => other } scala> succAny(2) res1: Any = 3 scala> succAny("two") res2: Any = two
  33. 33. Exception handling Unsurprisingly, exception handling is done using pattern matching: try { val f = new FileInputStream("f.txt") println(f.read()) f.close() } catch { _ is a wildcard case _: FileNotFoundException => println("not found") case e: IOException => println("other error: " + e) }
  34. 34. Functional programming in Scala
  35. 35. What is FP? The functional style of programming is one that relies on mathematical functions as the basic building block of programs. In mathematics, a function always returns the same result when applied to the same arguments. Therefore, the functional style of programming strongly discourages the use of side-effects – i.e. variables and other kinds of mutable data.
  36. 36. What is a FPL? A functional programming language is one that encourages the functional style of programming by: • offering first-class functions that can be manipulated like any other value, • providing lightweight syntax to define arbitrarily-nested functions, • discouraging the use of side-effects, for example by providing libraries of immutable data-structures.
  37. 37. Why is FP interesting? Side-effects complicate several classes of programs, like: • concurrent programs with shared, mutable state, • programs that need to do “time travel”, e.g. interactive programs with undo, SCMs, … • programs that need to work on a consistent state of some data, e.g. a live backup program, • etc.
  38. 38. A trait for functions trait Function1[F, T] { f => def apply(x: F): T new name for this def compose[F2](g: Function1[F2, F]) : Function1[F2, T] = new Function1[F2, T] { def apply(x: F2): T = f.apply(g.apply(x)) } override def toString = "<fun>" }
  39. 39. Using functions as values scala> val succ = new Fun[Int,Int] { def apply(x: Int) = x + 1 } succ: …with Function1[Int,Int] = <fun> scala> val twice = new Fun[Int,Int] { def apply(x: Int) = x + x } twice: …with Function1[Int,Int] =<fun> scala> succ.apply(6) res1: Int = 7 scala> twice.apply(5) res2: Int = 10 scala> (succ compose twice).apply(5) res3: Int = 11
  40. 40. se ! Using functions as values W or ks ,b ut w ay to o ve rb o scala> val succ = new Fun[Int,Int] { def apply(x: Int) = x + 1 } succ: …with Function1[Int,Int] = <fun> scala> val twice = new Fun[Int,Int] { def apply(x: Int) = x + x } twice: …with Function1[Int,Int] =<fun> scala> succ.apply(6) res1: Int = 7 scala> twice.apply(5) res2: Int = 10 scala> (succ compose twice).apply(5) res3: Int = 11
  41. 41. Functional syntactic sugar anonymous function scala> val succ = { x: Int => x + 1 } succ: (Int) => Int = <function1> a.k.a. Function1[Int, Int] scala> val twice = { x: Int => x + x } twice: (Int) => Int = <function1> scala> (succ compose twice)(5) res1: Int = 11 implicit apply
  42. 42. Partial application Function values can also be created by applying existing functions or methods to a (possibly empty) subset of their arguments: scala> val succ: Int=>Int = _ + 1 succ: (Int) => Int = <function1> scala> val toStr: Any=>String = _.toString toStr: (Any) => String = <function1> scala> toStr(0123) res0: String = 83
  43. 43. Collections as functions Most collections are functions: • Seq[T] has type Int=>T, • Map[K,V] has type K=>V, • Set[T] has type T=>Boolean. This explains the common notation to access their elements: it’s simply function application!
  44. 44. Operating on collections Functional values are ideal to operate on collections. Examples: scala> val s = Seq(1,2,3,4,5) scala> s map (_ + 1) res1: Seq[Int] = List(2, 3, 4, 5, 6) scala> s reduceLeft (_ * _) res2: Int = 120 scala> s filter (_ % 2 == 0) res3: Seq[Int] = List(2, 4) scala> s count (_ > 3) res4: Int = 2 scala> s forall (_ < 10) res5: Boolean = true
  45. 45. Project Euler: problem 8
  46. 46. Solving problem 8 val n = "7316717653133062491922511967442…" val digits = s.toList map (_.asDigit) def prods(l: List[Int]): List[Int] = l match { case a :: (t@(b :: c :: d :: e :: _)) => (a * b * c * d * e) :: prods(t) case _ => List() } prods(digits) reduceLeft (_ max _)
  47. 47. For loops translation The for notation is pure syntactic sugar. The example: for (user <- users if (user.isMale && user.age > 30)) yield user.name is automatically expanded to: users .filter(user => user.isMale && user.age > 30) .map(user => user.name)
  48. 48. Implicits
  49. 49. Scala implicits Scala offers two notions of implicit entities that are automatically inserted by the compiler in certain contexts: • Implicit conversions, which can be applied automatically to transform a type-incorrect expression into a type-correct one. • Implicit parameters, which can be automatically passed to a function.
  50. 50. Implicit conversions An implicit conversion from Int to Rational can be added to the latter’s companion object: object Rational { …as before implicit def i2r(i: Int): Rational = Rational(i) } scala> 2 + Rational(1,3) // i2r(2) + … res2: Rational = 7/3 scala> Rational(1,3) + 3 // … + i2r(3) res3: Rational = 10/3
  51. 51. “Pimp my library” Implicit conversions make it possible to “augment” existing classes by implicitly wrapping them – known as the Pimp my library pattern. This technique is heavily used in the standard library to improve anemic Java classes (e.g. String, Integer, Boolean, arrays, etc.). scala> "1337" strings are really Java strings res1: java.lang.String = 1337 implicit conversion scala> "1337".toInt res2: Int = 1337
  52. 52. Implicit parameters repeated parameter def max[T](xs: T*) (implicit ord: Ordering[T]): T = xs reduceLeft ord.max implicitly Ordering.Int scala> max(4, -2, 12, 25, 7, -1, 2) res1: Int = 25 scala> max(4, -2, 12, 25, 7, -1, 2) (Ordering.Int.reverse) res2: Int = -2 scala> max(1 to 20 : _*) res3: Int = 20 pass all elements as separate arguments
  53. 53. Working with XML data
  54. 54. XML literals Scala supports XML literals, which are translated to instances of various classes in scala.xml. scala> val hello = <p>Hello <b>world</b></p> hello: scala.xml.Elem = <p>Hello <b>world</b></p> scala> val name = "Roger&Co." name: java.lang.String = Roger&Co. scala> val hello = arbitrary Scala expression <p>Hello <b>{ name }</b></p> hello: scala.xml.Elem = <p>Hello <b>Roger&amp;Co.</b></p>
  55. 55. XPath-like queries scala> val users = <users> <user name="Roger" age="12"/> <user name="Mary" age="44"/> <user name="Jean" age="12"/> </users> scala> users "@name" res1: scala.xml.NodeSeq = RogerMaryJean scala> (users "@age") map (_.toString.toInt) reduceLeft (_ max _) res2: Int = 44
  56. 56. XML pattern matching def parseRow(r: xml.Node): (String, Int) = r match { case <tr><td>{ name }</td> <td>{ age }</td></tr> => (name.text, age.text.toInt) } scala> val table = <table> <tr><td>Roger</td><td>12</td></tr> <tr><td>Mary</td><td>44</td></tr> </table> scala> (table "tr") map parseRow res1: Seq[(String, Int)] = List((Roger,12), (Mary,44))
  57. 57. Testing with ScalaCheck
  58. 58. Properties for rationals The operations we defined on rationals should satisfy several properties: • ∀x, y ∈ Q: x + 0 = 0 + x = x • ∀x, y ∈ Q: x + (y + z) = (x + y) + z • etc. ScalaCheck makes it possible to express such properties and test them on random rationals. Extensive use of implicits keep the client code very concise.
  59. 59. Properties for rationals object RatProps extends Properties("Rat") { property("+ left unit") = Prop.forAll((x: Rational) => 0 + x == x) property("+ right unit") = Prop.forAll((x: Rational) => x + 0 == x) property("+ associativity") = Prop.forAll((x: Rational, y: Rational, z: Rational) => (x + y) + z == x + (y + z)) }
  60. 60. Generating rationals ScalaCheck doesn’t know how to generate arbitrary rationals, but we can easily define a generator for them: implicit def arbRat: Arbitrary[Rational] = Arbitrary { Gen.sized(sz => for (n <- Gen.choose(-sz, sz); d <- Gen.choose(-sz, sz) suchThat (_ != 0)) yield Rational(n, d)) }
  61. 61. Testing rationals % + + + scala Rat.+ Rat.+ Rat.+ RatProps left unit: OK, passed 100 tests. right unit: OK, passed 100 tests. associativity: OK, passed 100 tests. When a property can be falsified (here the incorrect property ∀x ∈ Q: x = 0), the counter-example is presented: ! Rat.wrong: Falsified after 0 passed tests. > ARG_0: 1/2
  62. 62. Further reading http://www.scala-lang.org/ Two books about Scala: • Programming in Scala by Odersky, Spoon & Venners • Programming Scala by Wampler & Payne One book about functional programming: • The Functional Approach to Programming by Cousineau, Mauny & Callaway
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×