SlideShare ist ein Scribd-Unternehmen logo
1 von 81
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

Weitere ähnliche Inhalte

Was ist angesagt?

Introduction to MatLab programming
Introduction to MatLab programmingIntroduction to MatLab programming
Introduction to MatLab programming
Damian T. Gordon
 
Introduction to Monads in Scala (2)
Introduction to Monads in Scala (2)Introduction to Monads in Scala (2)
Introduction to Monads in Scala (2)
stasimus
 

Was ist angesagt? (20)

Chapter 5
Chapter 5Chapter 5
Chapter 5
 
Introduction to matlab lecture 2 of 4
Introduction to matlab lecture 2 of 4Introduction to matlab lecture 2 of 4
Introduction to matlab lecture 2 of 4
 
16. Arrays Lists Stacks Queues
16. Arrays Lists Stacks Queues16. Arrays Lists Stacks Queues
16. Arrays Lists Stacks Queues
 
Monoids - Part 2 - with examples using Scalaz and Cats
Monoids - Part 2 - with examples using Scalaz and CatsMonoids - Part 2 - with examples using Scalaz and Cats
Monoids - Part 2 - with examples using Scalaz and Cats
 
Scala categorytheory
Scala categorytheoryScala categorytheory
Scala categorytheory
 
First-Class Patterns
First-Class PatternsFirst-Class Patterns
First-Class Patterns
 
Ch3
Ch3Ch3
Ch3
 
Introduction to MatLab programming
Introduction to MatLab programmingIntroduction to MatLab programming
Introduction to MatLab programming
 
Cats in Scala
Cats in ScalaCats in Scala
Cats in Scala
 
Matlab solved problems
Matlab solved problemsMatlab solved problems
Matlab solved problems
 
N-Queens Combinatorial Problem - Polyglot FP for fun and profit - Haskell and...
N-Queens Combinatorial Problem - Polyglot FP for fun and profit - Haskell and...N-Queens Combinatorial Problem - Polyglot FP for fun and profit - Haskell and...
N-Queens Combinatorial Problem - Polyglot FP for fun and profit - Haskell and...
 
Introduction to matlab lecture 3 of 4
Introduction to matlab lecture 3 of 4Introduction to matlab lecture 3 of 4
Introduction to matlab lecture 3 of 4
 
O caml2014 leroy-slides
O caml2014 leroy-slidesO caml2014 leroy-slides
O caml2014 leroy-slides
 
One Monad to Rule Them All
One Monad to Rule Them AllOne Monad to Rule Them All
One Monad to Rule Them All
 
Scala Collections : Java 8 on Steroids
Scala Collections : Java 8 on SteroidsScala Collections : Java 8 on Steroids
Scala Collections : Java 8 on Steroids
 
Introduction to Monads in Scala (2)
Introduction to Monads in Scala (2)Introduction to Monads in Scala (2)
Introduction to Monads in Scala (2)
 
Matlab Functions
Matlab FunctionsMatlab Functions
Matlab Functions
 
Scala Bootcamp 1
Scala Bootcamp 1Scala Bootcamp 1
Scala Bootcamp 1
 
Getting Started With Scala
Getting Started With ScalaGetting Started With Scala
Getting Started With Scala
 
19. Java data structures algorithms and complexity
19. Java data structures algorithms and complexity19. Java data structures algorithms and complexity
19. Java data structures algorithms and complexity
 

Andere mochten auch

Writing DSL's in Scala
Writing DSL's in ScalaWriting DSL's in Scala
Writing DSL's in Scala
Abhijit Sharma
 
Real-World Scala Design Patterns
Real-World Scala Design PatternsReal-World Scala Design Patterns
Real-World Scala Design Patterns
NLJUG
 
Types by Adform Research, Saulius Valatka
Types by Adform Research, Saulius ValatkaTypes by Adform Research, Saulius Valatka
Types by Adform Research, Saulius Valatka
Vasil Remeniuk
 
Variance in scala
Variance in scalaVariance in scala
Variance in scala
LyleK
 

Andere mochten auch (20)

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

Ähnlich wie Simple Scala DSLs

Core java by a introduction sandesh sharma
Core java by a introduction sandesh sharmaCore java by a introduction sandesh sharma
Core java by a introduction sandesh sharma
Sandesh Sharma
 
Java concepts and questions
Java concepts and questionsJava concepts and questions
Java concepts and questions
Farag Zakaria
 

Ähnlich wie Simple Scala DSLs (20)

Functional Programming With Scala
Functional Programming With ScalaFunctional Programming With Scala
Functional Programming With Scala
 
Core java by a introduction sandesh sharma
Core java by a introduction sandesh sharmaCore java by a introduction sandesh sharma
Core java by a introduction sandesh sharma
 
Functional programming with Scala
Functional programming with ScalaFunctional programming with Scala
Functional programming with Scala
 
Java 8
Java 8Java 8
Java 8
 
Ifi7184 lesson3
Ifi7184 lesson3Ifi7184 lesson3
Ifi7184 lesson3
 
White Box testing by Pankaj Thakur, NITTTR Chandigarh
White Box testing by Pankaj Thakur, NITTTR ChandigarhWhite Box testing by Pankaj Thakur, NITTTR Chandigarh
White Box testing by Pankaj Thakur, NITTTR Chandigarh
 
Scilab as a calculator
Scilab as a calculatorScilab as a calculator
Scilab as a calculator
 
Methods
MethodsMethods
Methods
 
java8
java8java8
java8
 
Functional programming-advantages
Functional programming-advantagesFunctional programming-advantages
Functional programming-advantages
 
Guava Overview. Part 1 @ Bucharest JUG #1
Guava Overview. Part 1 @ Bucharest JUG #1 Guava Overview. Part 1 @ Bucharest JUG #1
Guava Overview. Part 1 @ Bucharest JUG #1
 
Lambdas puzzler - Peter Lawrey
Lambdas puzzler - Peter LawreyLambdas puzzler - Peter Lawrey
Lambdas puzzler - Peter Lawrey
 
Java concepts and questions
Java concepts and questionsJava concepts and questions
Java concepts and questions
 
Arrays and its properties IN SWIFT
Arrays and its properties IN SWIFTArrays and its properties IN SWIFT
Arrays and its properties IN SWIFT
 
New Functional Features of Java 8
New Functional Features of Java 8New Functional Features of Java 8
New Functional Features of Java 8
 
ScalaLanguage_ch_4_5.pptx
ScalaLanguage_ch_4_5.pptxScalaLanguage_ch_4_5.pptx
ScalaLanguage_ch_4_5.pptx
 
Scala ntnu
Scala ntnuScala ntnu
Scala ntnu
 
Java8: what's new and what's hot
Java8: what's new and what's hotJava8: what's new and what's hot
Java8: what's new and what's hot
 
JavaScript(Es5) Interview Questions & Answers
JavaScript(Es5)  Interview Questions & AnswersJavaScript(Es5)  Interview Questions & Answers
JavaScript(Es5) Interview Questions & Answers
 
Wien15 java8
Wien15 java8Wien15 java8
Wien15 java8
 

Kürzlich hochgeladen

Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 

Kürzlich hochgeladen (20)

Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 

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

Hinweis der Redaktion