SlideShare a Scribd company logo
Simple Scala DSLs

      May 21, 2010




          1
A Definition




              2
A Definition

A DSL is a custom way to represent logic designed to
solve a specific problem.




                           2
A Definition

A DSL is a custom way to represent logic designed to
solve a specific problem.



I’m going to try and give you tools to stretch Scala’s
syntax to match the way you think about the logic of your
specific problem.




                            2
Key Scala features

• Syntactic sugar

• Implicit methods

• Options

• Higher order functions



                           3
Syntactic Sugar

You can omit . and () for any method which takes a single
parameter.

map get “key” == map.get(“key”)




                            4
Syntactic Sugar

Methods whose names end in : bind to the right.

“key” other: obj == obj.other:(“value”)

val newList = item :: oldList
val newList = oldList.::(item)




                           5
Syntactic Sugar

the apply() method

a(b) == a.apply(b)

map(“key”)     ==    map.apply(“key”)




                          6
Syntactic Sugar

the update() method

a(b) = c == a.update(b, c)
a(b, c) = d == a.update(b, c, d)

map(“key”) = “value” ==
   map.update(“key”, “value”)




                      7
Syntactic Sugar

setters and getters
object X { var y = 0 }
object X {
   private var _z: Int = 0
   def y = _z
   def y_=(i: Int) = _z = i
}
X.y => 0
X.y = 1 => Unit
X.y => 1
                      8
Syntactic Sugar

tuples

(a, b) == Tuple2[A,B](a, b)
(a, b, c) == Tuple3[A,B,C](a, b, c)

val (a, b) = sometuple   // extracts




                     9
Syntactic Sugar
unapply() - used to extract values in pattern matching
object Square {
  def unapply(p: Pair[Int, Int]) = p match {
    case (x, y) if x == y => Some(x)
    case _ => None
  }
}
(2, 2) match {
  case Square(side) => side*side
  case _ => -1
}                        10
Syntactic Sugar
varargs - sugar for a variable length array

def join(arr: String*) = arr.mkString(“,”)
join(“a”) => “a”
join(“a”, “b”) => “a,b”

def join(arr: Array[String]) =
arr.mkString(“,”)
join(Array(“a”, “b”)) => “a,b”


                             11
Syntactic Sugar
unapplySeq() - an extractor that supports vararg matching

object Join {
  def apply(l: String*) = l.mkString(“,”)
  def unapplySeq(s: String) =
    Some(s.split(“,”))
}
Join(“1”, “2”, “3”) match {
  case Join(“1”, _*) => println(“starts w/1”)
  case _ => println(“doesn’t start w/1”)
}
                           12
Syntactic Sugar




                  13
Syntactic Sugar
Case Classes are regular classes which export their
constructor parameters and which provide a recursive
decomposition mechanism via pattern matching.




                           13
Syntactic Sugar
Case Classes are regular classes which export their
constructor parameters and which provide a recursive
decomposition mechanism via pattern matching.

case class Square(side: Int)




                           13
Syntactic Sugar
Case Classes are regular classes which export their
constructor parameters and which provide a recursive
decomposition mechanism via pattern matching.

case class Square(side: Int)
val s = Square(2) // apply() is defined




                           13
Syntactic Sugar
Case Classes are regular classes which export their
constructor parameters and which provide a recursive
decomposition mechanism via pattern matching.

case class Square(side: Int)
val s = Square(2) // apply() is defined
s.side => 2        // member is exported




                           13
Syntactic Sugar
Case Classes are regular classes which export their
constructor parameters and which provide a recursive
decomposition mechanism via pattern matching.

case class Square(side: Int)
val s = Square(2) // apply() is defined
s.side => 2        // member is exported
val Square(x) = s // unapply() is defined




                           13
Syntactic Sugar
Case Classes are regular classes which export their
constructor parameters and which provide a recursive
decomposition mechanism via pattern matching.

case class Square(side: Int)
val s = Square(2) // apply() is defined
s.side => 2        // member is exported
val Square(x) = s // unapply() is defined
s.toString ==> “Square(2)”



                           13
Syntactic Sugar
Case Classes are regular classes which export their
constructor parameters and which provide a recursive
decomposition mechanism via pattern matching.

case class Square(side: Int)
val s = Square(2) // apply() is defined
s.side => 2        // member is exported
val Square(x) = s // unapply() is defined
s.toString ==> “Square(2)”
s.hashCode ==> 630363263

                           13
Syntactic Sugar
Case Classes are regular classes which export their
constructor parameters and which provide a recursive
decomposition mechanism via pattern matching.

case class Square(side: Int)
val s = Square(2) // apply() is defined
s.side => 2        // member is exported
val Square(x) = s // unapply() is defined
s.toString ==> “Square(2)”
s.hashCode ==> 630363263
s == Square(2) ==> true
                           13
Syntactic Sugar




                  14
Syntactic Sugar
Many classes can be used in for comprehensions because
they implement some combination of:

map[B](f: (A) => B): Option[B]
flatMap[B](f: (A) => Option[B]): Option[B]
filter(p: (A) => Boolean): Option[A]
foreach(f: (A) => Unit): Unit




                          14
Syntactic Sugar
Many classes can be used in for comprehensions because
they implement some combination of:

map[B](f: (A) => B): Option[B]
flatMap[B](f: (A) => Option[B]): Option[B]
filter(p: (A) => Boolean): Option[A]
foreach(f: (A) => Unit): Unit

for { i <- List(1,2,3)
      val x = i * 3
      if x % 2 == 0 } yield x          ==> List(6)

List(1,2,3).map(_ * 3).filter(_ % 2 == 0)
  ==> List(6)             14
Implicit Methods
Implicit methods are a compromise between the
closed approach to extension of Java and the open
approach to extension in Ruby.

Implicit Methods are:




                           15
Implicit Methods
Implicit methods are a compromise between the
closed approach to extension of Java and the open
approach to extension in Ruby.

Implicit Methods are:

• lexically scoped / non-global




                            15
Implicit Methods
Implicit methods are a compromise between the
closed approach to extension of Java and the open
approach to extension in Ruby.

Implicit Methods are:

• lexically scoped / non-global
• statically typed



                            15
Implicit Methods
Implicit methods are inserted by the compiler under
the following rules:




                            16
Implicit Methods
Implicit methods are inserted by the compiler under
the following rules:

   • they are in scope




                            16
Implicit Methods
Implicit methods are inserted by the compiler under
the following rules:

   • they are in scope
   • the selection is unambiguous




                            16
Implicit Methods
Implicit methods are inserted by the compiler under
the following rules:

   • they are in scope
   • the selection is unambiguous
   • it is not already in an implicit i.e. no nesting




                              16
Implicit Methods
Implicit methods are inserted by the compiler under
the following rules:

   • they are in scope
   • the selection is unambiguous
   • it is not already in an implicit i.e. no nesting
   • the code does not compile as written


                              16
Implicit Methods: Usage

Extending Abstractions: Java

class IntWrapper(int i) {
  int timesTen() {
    return i * 10;
  }
}

int i = 2;
new IntWrapper(i).timesTen();



                          17
Implicit Methods: Usage

Extending Abstractions: Java

Java’s abstractions are totally sealed and we must use
explicit wrapping each time we wish to extend them.

Pros: safe

Cons: repetitive boilerplate at each call site




                             18
Implicit Methods: Usage

Extending Abstractions: Ruby

class Int
  def timesTen
    self * 10
  end
end

i = 2
i.timesTen



                          19
Implicit Methods: Usage

Extending Abstractions: Ruby

Ruby’s abstractions are totally open. We can modify
the behavior of existing classes and objects in pretty
much any way we want.

Pros: declarative, powerful and flexible

Cons: easily abused and can be extremely difficult to
debug



                            20
Implicit Methods: Usage

Extending Abstractions: Scala

class IntWrapper(i: Int) {
  def timesTen = i * 10
}

implicit def wrapint(i: Int) =
  new IntWrapper(i)

val i = 2
i.timesTen


                           21
Implicit Methods: Usage

Extending Abstractions: Scala

Scala’s approach is both powerful and safe. While it is
certainly possible to abuse, it naturally encourages a
safer approach through lexical scoping.

Pros: more powerful than java, safer than ruby

Cons: can result in unexpected behavior if not tightly
scoped



                            22
Implicit Methods: Usage

Normalizing parameters

def remainder[T <: Double](num: T): Double =
num - num.floor




                         23
Implicit Methods: Usage

Normalizing parameters

def remainder[T <: Double](num: T): Double =
num - num.floor

remainder(.4)       ==> 0




                         23
Implicit Methods: Usage

Normalizing parameters

def remainder[T <: Double](num: T): Double =
num - num.floor

remainder(.4)       ==> 0

remainder(1.2)      ==> 1.2




                         23
Implicit Methods: Usage

Normalizing parameters

def remainder[T <: Double](num: T): Double =
num - num.floor

remainder(.4)       ==> 0

remainder(1.2)      ==> 1.2

remainder(120d) ==> 0



                         23
Implicit Methods: Usage

Normalizing parameters




                         24
Implicit Methods: Usage

Normalizing parameters

remainder(120) ==> error: inferred
type arguments [Int] do not conform to
method remainder's type parameter
bounds [T <: Double]




                         24
Implicit Methods: Usage

Normalizing parameters

remainder(120) ==> error: inferred
type arguments [Int] do not conform to
method remainder's type parameter
bounds [T <: Double]

implicit def i2d(i: Int): Double =
i.toDouble




                         24
Implicit Methods: Usage

Normalizing parameters

remainder(120) ==> error: inferred
type arguments [Int] do not conform to
method remainder's type parameter
bounds [T <: Double]

implicit def i2d(i: Int): Double =
i.toDouble

remainder(120)      ==> 0

                         24
Options

Options are scala’s answer to null.

Options are a very simple, 3-part class hierarchy:




                            25
Options

Options are scala’s answer to null.

Options are a very simple, 3-part class hierarchy:


• sealed abstract class Option[+A] extends
Product




                            25
Options

Options are scala’s answer to null.

Options are a very simple, 3-part class hierarchy:


• sealed abstract class Option[+A] extends
Product

• case final class Some[+A](val x : A)
extends Option[A]



                            25
Options

Options are scala’s answer to null.

Options are a very simple, 3-part class hierarchy:


• sealed abstract class Option[+A] extends
Product

• case final class Some[+A](val x : A)
extends Option[A]

• case object None extends Option[Nothing]
                            25
Options: Common Methods

def get: A

Some(1).get
 ==> 1

None.get
 ==> java.util.NoSuchElementException!




                   26
Options: Common Methods

def getOrElse[B >: A](default: => B): B

Some(1).getOrElse(2)
 ==> 1

None.getOrElse(2)
 ==> 2




                    27
Options: Common Methods

def map[B](f: (A) => B): Option[B]

Some(1).map(_.toString)
 ==> Some(“1”)

None.map(_.toString)
 ==> None




                   28
Options: Usage

Replacing Null Checks

A (contrived) Java example:

int result = -1;
int x = calcX();
if (x != null) {
  int y = calcY();
  if (y != null) {
    result = x * y;
  }
}
                              29
Options: Usage

Replacing Null Checks

def calcX: Option[Int]
def calcY: Option[Int]

for {
  val x <- Some(3)
  val y <- Some(2)
} yield x * y

 ==> Some(6)


                        30
Options: Usage

Replacing Null Checks

for {
  val x <- None
  val y <- Some(2)
} yield x * y

 ==> None




                        31
Options: Usage

Replacing Null Checks

(for {
  val x <- None
  val y <- Some(2)
} yield x * y).getOrElse(-1)

 ==> -1




                        32
Options: Usage

Replacing Null Checks

(for {
  val x <- Some(3)
  val y <- Some(2)
} yield x * y).getOrElse(-1)

 ==> 6




                        33
Options: Usage

Safely Transforming Values

val x: Option[Int] = calcOptionalX()

def xform(i: Int): Int




                             34
Options: Usage

Safely Transforming Values

val x: Option[Int] = calcOptionalX()

def xform(i: Int): Int


(x map xform) getOrElse -1




                             34
Options: Usage

Safely Transforming Values

val x: Option[Int] = calcOptionalX()

def xform(i: Int): Int


(x map xform) getOrElse -1

(for (i <- x) yield xform(i)).getOrElse(-1)


                             34
Implicits + Options




                      35
Implicits + Options

val m = Map(“1” -> 1,“map” -> Map(“2” -> 2))




                      35
Implicits + Options

val m = Map(“1” -> 1,“map” -> Map(“2” -> 2))


We’d like to be able to access the map like this:

m/”key1”/”key2”/”key3”




                            35
Implicits + Options

val m = Map(“1” -> 1,“map” -> Map(“2” -> 2))


We’d like to be able to access the map like this:

m/”key1”/”key2”/”key3”


But, we’d like to not have to constantly check nulls or
Options.



                            35
Implicits + Options

class MapWrapper(map: Map[String, Any]) {
  def /(s: String): Option[Any] = map.get(s)
}

implicit def a2mw(a: Any) = new
MapWrapper(a.asInstanceOf[Map[String, Any]])




                      36
Implicits + Options

class MapWrapper(map: Map[String, Any]) {
  def /(s: String): Option[Any] = map.get(s)
}

implicit def a2mw(a: Any) = new
MapWrapper(a.asInstanceOf[Map[String, Any]])

m/”a” ==> None




                      36
Implicits + Options

class MapWrapper(map: Map[String, Any]) {
  def /(s: String): Option[Any] = map.get(s)
}

implicit def a2mw(a: Any) = new
MapWrapper(a.asInstanceOf[Map[String, Any]])

m/”a” ==> None

m/”1” ==> Some(1)


                      36
Implicits + Options

class MapWrapper(map: Map[String, Any]) {
  def /(s: String): Option[Any] = map.get(s)
}

implicit def a2mw(a: Any) = new
MapWrapper(a.asInstanceOf[Map[String, Any]])

m/”a” ==> None

m/”1” ==> Some(1)

m/”map”/”2” ==> ClassCastException!
                      36
Implicits + Options

class OptionMapWrapper(
    o: Option[MapWrapper]) {
  def /(s: String) = o match {
    case Some(mw) => mw/s
    case _ => None
  }
}
implicit def o2omw(o: Option[Any]) = new
OptionMapWrapper(o map a2mw)




                      37
Implicits + Options

class OptionMapWrapper(
    o: Option[MapWrapper]) {
  def /(s: String) = o match {
    case Some(mw) => mw/s
    case _ => None
  }
}
implicit def o2omw(o: Option[Any]) = new
OptionMapWrapper(o map a2mw)

m/”map”/”2”   ==> Some(2)


                      37
Implicits + Options

class OptionMapWrapper(
    o: Option[MapWrapper]) {
  def /(s: String) = o match {
    case Some(mw) => mw/s
    case _ => None
  }
}
implicit def o2omw(o: Option[Any]) = new
OptionMapWrapper(o map a2mw)

m/”map”/”2”   ==> Some(2)

m/”map”/”next”/”blah”      ==> None
                      37
Higher Order Functions
Higher order functions are functions that:

• take functions as parameters
AND / OR

• result in a function




                             38
Higher Order Functions




                    39
Higher Order Functions
Let’s say we’d like to write a little system for easily running
statements asynchronously via either threads or actors.




                              39
Higher Order Functions
Let’s say we’d like to write a little system for easily running
statements asynchronously via either threads or actors.


What we’d like to get to:

run (println(“hello”)) using threads

run (println(“hello”)) using actors




                              39
Higher Order Functions
trait RunCtx {
  def run(f: => Unit): Unit
}

class Runner(f: => Unit) {
  def using(ctx: RunCtx) = ctx run f
}

def run(f: => Unit) = new Runner(f)




                     40
Higher Order Functions
object actors extends RunCtx {
  def run(f: => Unit) =
    scala.actors.Actor.actor(f)
}

object threads extends RunCtx {
  def run(f: => Unit) = {
    object t extends Thread {
      override def run = f
    }
    t.start
  }
}
                     41
Thank You!


email: lincoln@hotpotato.com
twitter: 11nc
hotpotato: lincoln


Questions?



                          42

More Related Content

PPT
basic concepts
PPTX
What is matlab
PDF
Monoids - Part 1 - with examples using Scalaz and Cats
PPT
Introduction to MATLAB
PDF
A taste of Functional Programming
PDF
Introduction to functional programming using Ocaml
PDF
Matlab commands
PPT
Intro matlab and convolution islam
basic concepts
What is matlab
Monoids - Part 1 - with examples using Scalaz and Cats
Introduction to MATLAB
A taste of Functional Programming
Introduction to functional programming using Ocaml
Matlab commands
Intro matlab and convolution islam

What's hot (20)

PDF
Chapter 5
PPTX
Introduction to matlab lecture 2 of 4
PPTX
16. Arrays Lists Stacks Queues
PDF
Monoids - Part 2 - with examples using Scalaz and Cats
PDF
Scala categorytheory
PDF
First-Class Patterns
PPT
Introduction to MatLab programming
PPTX
Cats in Scala
PDF
Matlab solved problems
PDF
N-Queens Combinatorial Problem - Polyglot FP for fun and profit - Haskell and...
PPTX
Introduction to matlab lecture 3 of 4
PDF
O caml2014 leroy-slides
PDF
One Monad to Rule Them All
PDF
Scala Collections : Java 8 on Steroids
PPTX
Introduction to Monads in Scala (2)
PPTX
Matlab Functions
PDF
Scala Bootcamp 1
PDF
Getting Started With Scala
PPTX
19. Java data structures algorithms and complexity
Chapter 5
Introduction to matlab lecture 2 of 4
16. Arrays Lists Stacks Queues
Monoids - Part 2 - with examples using Scalaz and Cats
Scala categorytheory
First-Class Patterns
Introduction to MatLab programming
Cats in Scala
Matlab solved problems
N-Queens Combinatorial Problem - Polyglot FP for fun and profit - Haskell and...
Introduction to matlab lecture 3 of 4
O caml2014 leroy-slides
One Monad to Rule Them All
Scala Collections : Java 8 on Steroids
Introduction to Monads in Scala (2)
Matlab Functions
Scala Bootcamp 1
Getting Started With Scala
19. Java data structures algorithms and complexity
Ad

Viewers also liked (20)

PPT
Writing DSL's in Scala
PDF
A Field Guide to DSL Design in Scala
PDF
Using Scala for building DSLs
PDF
Domain specific languages and Scala
ODP
Type Parameterization
PPTX
Effective Programming In Scala
PDF
Scala collections
PDF
So various polymorphism in Scala
PPTX
Scala’s implicits
PDF
Real-World Scala Design Patterns
PDF
Scala Implicits - Not to be feared
PPTX
Types by Adform Research, Saulius Valatka
PDF
Variance in scala
PDF
Scala Types of Types @ Lambda Days
PPTX
JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)
PDF
Big Data Day LA 2016/ Hadoop/ Spark/ Kafka track - Data Provenance Support in...
PDF
Python and Bigdata - An Introduction to Spark (PySpark)
PPTX
Advanced Functional Programming in Scala
PDF
Introduction to Spark Internals
PDF
Everyday I'm Shuffling - Tips for Writing Better Spark Programs, Strata San J...
Writing DSL's in Scala
A Field Guide to DSL Design in Scala
Using Scala for building DSLs
Domain specific languages and Scala
Type Parameterization
Effective Programming In Scala
Scala collections
So various polymorphism in Scala
Scala’s implicits
Real-World Scala Design Patterns
Scala Implicits - Not to be feared
Types by Adform Research, Saulius Valatka
Variance in scala
Scala Types of Types @ Lambda Days
JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)
Big Data Day LA 2016/ Hadoop/ Spark/ Kafka track - Data Provenance Support in...
Python and Bigdata - An Introduction to Spark (PySpark)
Advanced Functional Programming in Scala
Introduction to Spark Internals
Everyday I'm Shuffling - Tips for Writing Better Spark Programs, Strata San J...
Ad

Similar to Simple Scala DSLs (20)

PDF
Introduction to Scala
PDF
7li7w devcon5
PDF
CodeFest 2010. Иноземцев И. — Fantom. Cross-VM Language
PDF
Seductions of Scala
PDF
Scala at GenevaJUG by Iulian Dragos
PPTX
Proposals for new function in Java SE 9 and beyond
PDF
Scala Paradigms
PDF
Scala for Java Developers - Intro
PDF
An Introduction to Scala for Java Developers
PDF
BCS SPA 2010 - An Introduction to Scala for Java Developers
PDF
(How) can we benefit from adopting scala?
PPT
Groovy presentation
PDF
Miles Sabin Introduction To Scala For Java Developers
PDF
A Brief Introduction to Scala for Java Developers
PDF
Scala for Java Programmers
ODP
Groovy intro for OUDL
PPTX
Softshake 2013: 10 reasons why java developers are jealous of Scala developers
PDF
scalaliftoff2009.pdf
PDF
scalaliftoff2009.pdf
PDF
scalaliftoff2009.pdf
Introduction to Scala
7li7w devcon5
CodeFest 2010. Иноземцев И. — Fantom. Cross-VM Language
Seductions of Scala
Scala at GenevaJUG by Iulian Dragos
Proposals for new function in Java SE 9 and beyond
Scala Paradigms
Scala for Java Developers - Intro
An Introduction to Scala for Java Developers
BCS SPA 2010 - An Introduction to Scala for Java Developers
(How) can we benefit from adopting scala?
Groovy presentation
Miles Sabin Introduction To Scala For Java Developers
A Brief Introduction to Scala for Java Developers
Scala for Java Programmers
Groovy intro for OUDL
Softshake 2013: 10 reasons why java developers are jealous of Scala developers
scalaliftoff2009.pdf
scalaliftoff2009.pdf
scalaliftoff2009.pdf

Recently uploaded (20)

PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PPTX
breach-and-attack-simulation-cybersecurity-india-chennai-defenderrabbit-2025....
PDF
Machine learning based COVID-19 study performance prediction
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
NewMind AI Weekly Chronicles - August'25 Week I
PDF
Advanced IT Governance
PDF
Empathic Computing: Creating Shared Understanding
PDF
solutions_manual_-_materials___processing_in_manufacturing__demargo_.pdf
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
Approach and Philosophy of On baking technology
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PPTX
Big Data Technologies - Introduction.pptx
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PDF
Review of recent advances in non-invasive hemoglobin estimation
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
breach-and-attack-simulation-cybersecurity-india-chennai-defenderrabbit-2025....
Machine learning based COVID-19 study performance prediction
Network Security Unit 5.pdf for BCA BBA.
NewMind AI Weekly Chronicles - August'25 Week I
Advanced IT Governance
Empathic Computing: Creating Shared Understanding
solutions_manual_-_materials___processing_in_manufacturing__demargo_.pdf
“AI and Expert System Decision Support & Business Intelligence Systems”
Approach and Philosophy of On baking technology
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Big Data Technologies - Introduction.pptx
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
Review of recent advances in non-invasive hemoglobin estimation
20250228 LYD VKU AI Blended-Learning.pptx
Chapter 3 Spatial Domain Image Processing.pdf
Reach Out and Touch Someone: Haptics and Empathic Computing

Simple Scala DSLs

  • 1. Simple Scala DSLs May 21, 2010 1
  • 3. A Definition A DSL is a custom way to represent logic designed to solve a specific problem. 2
  • 4. A Definition A DSL is a custom way to represent logic designed to solve a specific problem. I’m going to try and give you tools to stretch Scala’s syntax to match the way you think about the logic of your specific problem. 2
  • 5. Key Scala features • Syntactic sugar • Implicit methods • Options • Higher order functions 3
  • 6. Syntactic Sugar You can omit . and () for any method which takes a single parameter. map get “key” == map.get(“key”) 4
  • 7. Syntactic Sugar Methods whose names end in : bind to the right. “key” other: obj == obj.other:(“value”) val newList = item :: oldList val newList = oldList.::(item) 5
  • 8. Syntactic Sugar the apply() method a(b) == a.apply(b) map(“key”) == map.apply(“key”) 6
  • 9. Syntactic Sugar the update() method a(b) = c == a.update(b, c) a(b, c) = d == a.update(b, c, d) map(“key”) = “value” == map.update(“key”, “value”) 7
  • 10. Syntactic Sugar setters and getters object X { var y = 0 } object X { private var _z: Int = 0 def y = _z def y_=(i: Int) = _z = i } X.y => 0 X.y = 1 => Unit X.y => 1 8
  • 11. Syntactic Sugar tuples (a, b) == Tuple2[A,B](a, b) (a, b, c) == Tuple3[A,B,C](a, b, c) val (a, b) = sometuple // extracts 9
  • 12. Syntactic Sugar unapply() - used to extract values in pattern matching object Square { def unapply(p: Pair[Int, Int]) = p match { case (x, y) if x == y => Some(x) case _ => None } } (2, 2) match { case Square(side) => side*side case _ => -1 } 10
  • 13. Syntactic Sugar varargs - sugar for a variable length array def join(arr: String*) = arr.mkString(“,”) join(“a”) => “a” join(“a”, “b”) => “a,b” def join(arr: Array[String]) = arr.mkString(“,”) join(Array(“a”, “b”)) => “a,b” 11
  • 14. Syntactic Sugar unapplySeq() - an extractor that supports vararg matching object Join { def apply(l: String*) = l.mkString(“,”) def unapplySeq(s: String) = Some(s.split(“,”)) } Join(“1”, “2”, “3”) match { case Join(“1”, _*) => println(“starts w/1”) case _ => println(“doesn’t start w/1”) } 12
  • 16. Syntactic Sugar Case Classes are regular classes which export their constructor parameters and which provide a recursive decomposition mechanism via pattern matching. 13
  • 17. Syntactic Sugar Case Classes are regular classes which export their constructor parameters and which provide a recursive decomposition mechanism via pattern matching. case class Square(side: Int) 13
  • 18. Syntactic Sugar Case Classes are regular classes which export their constructor parameters and which provide a recursive decomposition mechanism via pattern matching. case class Square(side: Int) val s = Square(2) // apply() is defined 13
  • 19. Syntactic Sugar Case Classes are regular classes which export their constructor parameters and which provide a recursive decomposition mechanism via pattern matching. case class Square(side: Int) val s = Square(2) // apply() is defined s.side => 2 // member is exported 13
  • 20. Syntactic Sugar Case Classes are regular classes which export their constructor parameters and which provide a recursive decomposition mechanism via pattern matching. case class Square(side: Int) val s = Square(2) // apply() is defined s.side => 2 // member is exported val Square(x) = s // unapply() is defined 13
  • 21. Syntactic Sugar Case Classes are regular classes which export their constructor parameters and which provide a recursive decomposition mechanism via pattern matching. case class Square(side: Int) val s = Square(2) // apply() is defined s.side => 2 // member is exported val Square(x) = s // unapply() is defined s.toString ==> “Square(2)” 13
  • 22. Syntactic Sugar Case Classes are regular classes which export their constructor parameters and which provide a recursive decomposition mechanism via pattern matching. case class Square(side: Int) val s = Square(2) // apply() is defined s.side => 2 // member is exported val Square(x) = s // unapply() is defined s.toString ==> “Square(2)” s.hashCode ==> 630363263 13
  • 23. Syntactic Sugar Case Classes are regular classes which export their constructor parameters and which provide a recursive decomposition mechanism via pattern matching. case class Square(side: Int) val s = Square(2) // apply() is defined s.side => 2 // member is exported val Square(x) = s // unapply() is defined s.toString ==> “Square(2)” s.hashCode ==> 630363263 s == Square(2) ==> true 13
  • 25. Syntactic Sugar Many classes can be used in for comprehensions because they implement some combination of: map[B](f: (A) => B): Option[B] flatMap[B](f: (A) => Option[B]): Option[B] filter(p: (A) => Boolean): Option[A] foreach(f: (A) => Unit): Unit 14
  • 26. Syntactic Sugar Many classes can be used in for comprehensions because they implement some combination of: map[B](f: (A) => B): Option[B] flatMap[B](f: (A) => Option[B]): Option[B] filter(p: (A) => Boolean): Option[A] foreach(f: (A) => Unit): Unit for { i <- List(1,2,3) val x = i * 3 if x % 2 == 0 } yield x ==> List(6) List(1,2,3).map(_ * 3).filter(_ % 2 == 0) ==> List(6) 14
  • 27. Implicit Methods Implicit methods are a compromise between the closed approach to extension of Java and the open approach to extension in Ruby. Implicit Methods are: 15
  • 28. Implicit Methods Implicit methods are a compromise between the closed approach to extension of Java and the open approach to extension in Ruby. Implicit Methods are: • lexically scoped / non-global 15
  • 29. Implicit Methods Implicit methods are a compromise between the closed approach to extension of Java and the open approach to extension in Ruby. Implicit Methods are: • lexically scoped / non-global • statically typed 15
  • 30. Implicit Methods Implicit methods are inserted by the compiler under the following rules: 16
  • 31. Implicit Methods Implicit methods are inserted by the compiler under the following rules: • they are in scope 16
  • 32. Implicit Methods Implicit methods are inserted by the compiler under the following rules: • they are in scope • the selection is unambiguous 16
  • 33. Implicit Methods Implicit methods are inserted by the compiler under the following rules: • they are in scope • the selection is unambiguous • it is not already in an implicit i.e. no nesting 16
  • 34. Implicit Methods Implicit methods are inserted by the compiler under the following rules: • they are in scope • the selection is unambiguous • it is not already in an implicit i.e. no nesting • the code does not compile as written 16
  • 35. Implicit Methods: Usage Extending Abstractions: Java class IntWrapper(int i) { int timesTen() { return i * 10; } } int i = 2; new IntWrapper(i).timesTen(); 17
  • 36. Implicit Methods: Usage Extending Abstractions: Java Java’s abstractions are totally sealed and we must use explicit wrapping each time we wish to extend them. Pros: safe Cons: repetitive boilerplate at each call site 18
  • 37. Implicit Methods: Usage Extending Abstractions: Ruby class Int def timesTen self * 10 end end i = 2 i.timesTen 19
  • 38. Implicit Methods: Usage Extending Abstractions: Ruby Ruby’s abstractions are totally open. We can modify the behavior of existing classes and objects in pretty much any way we want. Pros: declarative, powerful and flexible Cons: easily abused and can be extremely difficult to debug 20
  • 39. Implicit Methods: Usage Extending Abstractions: Scala class IntWrapper(i: Int) { def timesTen = i * 10 } implicit def wrapint(i: Int) = new IntWrapper(i) val i = 2 i.timesTen 21
  • 40. Implicit Methods: Usage Extending Abstractions: Scala Scala’s approach is both powerful and safe. While it is certainly possible to abuse, it naturally encourages a safer approach through lexical scoping. Pros: more powerful than java, safer than ruby Cons: can result in unexpected behavior if not tightly scoped 22
  • 41. Implicit Methods: Usage Normalizing parameters def remainder[T <: Double](num: T): Double = num - num.floor 23
  • 42. Implicit Methods: Usage Normalizing parameters def remainder[T <: Double](num: T): Double = num - num.floor remainder(.4) ==> 0 23
  • 43. Implicit Methods: Usage Normalizing parameters def remainder[T <: Double](num: T): Double = num - num.floor remainder(.4) ==> 0 remainder(1.2) ==> 1.2 23
  • 44. Implicit Methods: Usage Normalizing parameters def remainder[T <: Double](num: T): Double = num - num.floor remainder(.4) ==> 0 remainder(1.2) ==> 1.2 remainder(120d) ==> 0 23
  • 46. Implicit Methods: Usage Normalizing parameters remainder(120) ==> error: inferred type arguments [Int] do not conform to method remainder's type parameter bounds [T <: Double] 24
  • 47. Implicit Methods: Usage Normalizing parameters remainder(120) ==> error: inferred type arguments [Int] do not conform to method remainder's type parameter bounds [T <: Double] implicit def i2d(i: Int): Double = i.toDouble 24
  • 48. Implicit Methods: Usage Normalizing parameters remainder(120) ==> error: inferred type arguments [Int] do not conform to method remainder's type parameter bounds [T <: Double] implicit def i2d(i: Int): Double = i.toDouble remainder(120) ==> 0 24
  • 49. Options Options are scala’s answer to null. Options are a very simple, 3-part class hierarchy: 25
  • 50. Options Options are scala’s answer to null. Options are a very simple, 3-part class hierarchy: • sealed abstract class Option[+A] extends Product 25
  • 51. Options Options are scala’s answer to null. Options are a very simple, 3-part class hierarchy: • sealed abstract class Option[+A] extends Product • case final class Some[+A](val x : A) extends Option[A] 25
  • 52. Options Options are scala’s answer to null. Options are a very simple, 3-part class hierarchy: • sealed abstract class Option[+A] extends Product • case final class Some[+A](val x : A) extends Option[A] • case object None extends Option[Nothing] 25
  • 53. Options: Common Methods def get: A Some(1).get ==> 1 None.get ==> java.util.NoSuchElementException! 26
  • 54. Options: Common Methods def getOrElse[B >: A](default: => B): B Some(1).getOrElse(2) ==> 1 None.getOrElse(2) ==> 2 27
  • 55. Options: Common Methods def map[B](f: (A) => B): Option[B] Some(1).map(_.toString) ==> Some(“1”) None.map(_.toString) ==> None 28
  • 56. Options: Usage Replacing Null Checks A (contrived) Java example: int result = -1; int x = calcX(); if (x != null) { int y = calcY(); if (y != null) { result = x * y; } } 29
  • 57. Options: Usage Replacing Null Checks def calcX: Option[Int] def calcY: Option[Int] for { val x <- Some(3) val y <- Some(2) } yield x * y ==> Some(6) 30
  • 58. Options: Usage Replacing Null Checks for { val x <- None val y <- Some(2) } yield x * y ==> None 31
  • 59. Options: Usage Replacing Null Checks (for { val x <- None val y <- Some(2) } yield x * y).getOrElse(-1) ==> -1 32
  • 60. Options: Usage Replacing Null Checks (for { val x <- Some(3) val y <- Some(2) } yield x * y).getOrElse(-1) ==> 6 33
  • 61. Options: Usage Safely Transforming Values val x: Option[Int] = calcOptionalX() def xform(i: Int): Int 34
  • 62. Options: Usage Safely Transforming Values val x: Option[Int] = calcOptionalX() def xform(i: Int): Int (x map xform) getOrElse -1 34
  • 63. Options: Usage Safely Transforming Values val x: Option[Int] = calcOptionalX() def xform(i: Int): Int (x map xform) getOrElse -1 (for (i <- x) yield xform(i)).getOrElse(-1) 34
  • 65. Implicits + Options val m = Map(“1” -> 1,“map” -> Map(“2” -> 2)) 35
  • 66. Implicits + Options val m = Map(“1” -> 1,“map” -> Map(“2” -> 2)) We’d like to be able to access the map like this: m/”key1”/”key2”/”key3” 35
  • 67. Implicits + Options val m = Map(“1” -> 1,“map” -> Map(“2” -> 2)) We’d like to be able to access the map like this: m/”key1”/”key2”/”key3” But, we’d like to not have to constantly check nulls or Options. 35
  • 68. Implicits + Options class MapWrapper(map: Map[String, Any]) { def /(s: String): Option[Any] = map.get(s) } implicit def a2mw(a: Any) = new MapWrapper(a.asInstanceOf[Map[String, Any]]) 36
  • 69. Implicits + Options class MapWrapper(map: Map[String, Any]) { def /(s: String): Option[Any] = map.get(s) } implicit def a2mw(a: Any) = new MapWrapper(a.asInstanceOf[Map[String, Any]]) m/”a” ==> None 36
  • 70. Implicits + Options class MapWrapper(map: Map[String, Any]) { def /(s: String): Option[Any] = map.get(s) } implicit def a2mw(a: Any) = new MapWrapper(a.asInstanceOf[Map[String, Any]]) m/”a” ==> None m/”1” ==> Some(1) 36
  • 71. Implicits + Options class MapWrapper(map: Map[String, Any]) { def /(s: String): Option[Any] = map.get(s) } implicit def a2mw(a: Any) = new MapWrapper(a.asInstanceOf[Map[String, Any]]) m/”a” ==> None m/”1” ==> Some(1) m/”map”/”2” ==> ClassCastException! 36
  • 72. Implicits + Options class OptionMapWrapper( o: Option[MapWrapper]) { def /(s: String) = o match { case Some(mw) => mw/s case _ => None } } implicit def o2omw(o: Option[Any]) = new OptionMapWrapper(o map a2mw) 37
  • 73. Implicits + Options class OptionMapWrapper( o: Option[MapWrapper]) { def /(s: String) = o match { case Some(mw) => mw/s case _ => None } } implicit def o2omw(o: Option[Any]) = new OptionMapWrapper(o map a2mw) m/”map”/”2” ==> Some(2) 37
  • 74. Implicits + Options class OptionMapWrapper( o: Option[MapWrapper]) { def /(s: String) = o match { case Some(mw) => mw/s case _ => None } } implicit def o2omw(o: Option[Any]) = new OptionMapWrapper(o map a2mw) m/”map”/”2” ==> Some(2) m/”map”/”next”/”blah” ==> None 37
  • 75. Higher Order Functions Higher order functions are functions that: • take functions as parameters AND / OR • result in a function 38
  • 77. Higher Order Functions Let’s say we’d like to write a little system for easily running statements asynchronously via either threads or actors. 39
  • 78. Higher Order Functions Let’s say we’d like to write a little system for easily running statements asynchronously via either threads or actors. What we’d like to get to: run (println(“hello”)) using threads run (println(“hello”)) using actors 39
  • 79. Higher Order Functions trait RunCtx { def run(f: => Unit): Unit } class Runner(f: => Unit) { def using(ctx: RunCtx) = ctx run f } def run(f: => Unit) = new Runner(f) 40
  • 80. Higher Order Functions object actors extends RunCtx { def run(f: => Unit) = scala.actors.Actor.actor(f) } object threads extends RunCtx { def run(f: => Unit) = { object t extends Thread { override def run = f } t.start } } 41
  • 81. Thank You! email: lincoln@hotpotato.com twitter: 11nc hotpotato: lincoln Questions? 42