taxonomy of scala
TRANSCRIPT
![Page 1: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/1.jpg)
A Taxonomy of ScalaStrangeLoop 2012
Jamie Allen@jamie_allen
http://github.com/jamie-allen/taxonomy-of-scala
![Page 2: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/2.jpg)
Agenda
• Goal• Object-Oriented Features• Pattern Matching• Functional Programming• Actors• Futures• Implicits• Type Theory• Macros• Category Theory
![Page 3: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/3.jpg)
Goal
Provide you with a reference point for many of the terms you hear in the Scala community
![Page 4: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/4.jpg)
How Programming in Scala Makes Me Feel
![Page 5: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/5.jpg)
How I Write Programs
• Pre-Scala:– Make it work– Make it work well– Make it work fast
• With Scala:– Make it work and work well– Make it work fast
![Page 6: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/6.jpg)
Object-Oriented Features
![Page 7: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/7.jpg)
Case Classes
case class Person(firstName: String = "Jamie", lastName: String = "Allen")
val jamieDoe = Person(lastName = "Doe") res0: Person = Person(Jamie,Doe)
• Data Transfer Objects (DTOs) done right• By default, class arguments are immutable & public• Should never be extended• Provide equals(), copy(), hashCode() and toString()
implementations• Don’t have to use new keyword to create instances• Named Parameters and Default arguments give us Builder pattern semantics
![Page 8: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/8.jpg)
Lazy Definitionslazy val calculatedValue = piToOneMillionDecimalPoints()
• Excellent for deferring expensive operations until they are needed
• Reducing initial footprint• Resolving ordering issues• Implemented with a guard field and
synchronization, ensuring it is created when necessary
![Page 9: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/9.jpg)
Importsimport scala.collection.immutable.Map
class Person(val fName: String, val lName: String) {import scala.collection.mutable.{Map => MMap}val cars: MMap[String, String] = MMap()...
}
• Can be anywhere in a class• Allow for selecting multiple classes from a package or using
wildcards• Aliasing• Order matters!
![Page 10: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/10.jpg)
Objectsobject Bootstrapper extends App { Person.createJamieAllen }
object Person { def createJamieAllen = new Person("Jamie", "Allen") def createJamieDoe = new Person("Jamie", "Doe") val aConstantValue = "A constant value”}
class Person(val firstName: String, val lastName: String)
• Singletons within a JVM process• No private constructor histrionics• Companion Objects, used for factories and constants
![Page 11: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/11.jpg)
The apply() methodArray(1, 2, 3)res0: Array[Int] = Array(1, 2, 3)
res0(1)res1: Int = 2
• In companion objects, it defines default behavior if no method is called on it
• In a class, it defines the same thing on an instance of the class
![Page 12: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/12.jpg)
Tuplesdef firstPerson = (1, Person(firstName = “Barbara”))val (num: Int, person: Person) = firstPerson
• Binds you to an implementation• Great way to group values without a DTO• How to return multiple values, but wrapped in
a single instance that you can bind to specific values
![Page 13: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/13.jpg)
Pattern Matching
![Page 14: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/14.jpg)
Pattern Matching Examplesname match { case "Lisa" => println("Found Lisa”) case Person("Bob") => println("Found Bob”) case "Karen" | "Michelle" => println("Found Karen or Michelle”) case Seq("Dave", "John") => println("Got Dave before John”) case Seq("Dave", "John", _*) => println("Got Dave before John”) case ("Susan", "Steve") => println("Got Susan and Steve”) case x: Int if x > 5 => println("got value greater than 5: " + x) case x => println("Got something that wasn't an Int: " + x) case _ => println("Not found”)}
• A gateway drug for Scala• Extremely powerful and readable• Not compiled down to lookup/table switch unless you
use the @switch annotation,
![Page 15: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/15.jpg)
Functional Programming
![Page 16: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/16.jpg)
Immutability
• Extends beyond marking instances final• You must not leak mutability
![Page 17: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/17.jpg)
Referential Transparency// Transparentval example1 = "jamie".reverseval example2 = example1.reverseprintln(example1 + example2) // eimajjamie
// Opaqueval example1 = new StringBuffer("Jamie").reverseval example2 = example1.reverseprintln(example1 append example2) // jamiejamie
• An expression is transparent if it can be replaced by its VALUE without changing the behavior of the program
• In math, all functions are referentially transparent
![Page 18: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/18.jpg)
Scala Collectionsval myMap = Map(1 -> "one", 2 -> "two", 3 -> "three")val mySet = Set(1, 4, 2, 8)val myList = List(1, 2, 8, 3, 3, 4)val myVector = Vector(1, 2, 3...)
• You have the choice of mutable or immutable collection instances, immutable by default
• Rich implementations, extremely flexible
![Page 19: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/19.jpg)
Rich Collection Functionalityval numbers = 1 to 20 // Range(1, 2, 3, ... 20)
numbers.head // Int = 1numbers.tail // Range(2, 3, 4, ... 20)numbers.take(5) // Range(1, 2, 3, 4, 5)numbers.drop(5) // Range(6, 7, 8, ... 20)
• There are many methods available to you in the Scala collections library
• Spend 5 minutes every day going over the ScalaDoc for one collection class
![Page 20: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/20.jpg)
Higher Order Functionsval names = List("Barb", "May", "Jon")
names map(_.toUpperCase)res0: List[java.lang.String] = List(BARB, MAY, JON)
• Really methods in Scala• Applying closures to collections
![Page 21: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/21.jpg)
Higher Order Functionsval names = List("Barb", "May", "Jon")
names map(_.toUpperCase)res0: List[java.lang.String] = List(BARB, MAY, JON)
names flatMap(_.toUpperCase)res1: List[Char] = List(B, A, R, B, M, A, Y, J, O, N)
names filter (_.contains("a"))res2: List[java.lang.String] = List(Barb, May)
val numbers = 1 to 20 // Range(1, 2, 3, ... 20)
numbers.groupBy(_ % 3)res3: Map[Int, IndexedSeq[Int]] = Map(1 -> Vector(1, 4, 7, 10, 13, 16, 19), 2 -> Vector(2, 5, 8, 11, 14, 17, 20), 0 -> Vector(3, 6, 9, 12, 15, 18))
![Page 22: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/22.jpg)
For Comprehensions
• Used for composing higher-order functions• As you chain higher-order functions, you may
find it easier to reason about them this way
val myNums = 1 to 20
for (i <- myNums) yield i + 1myNums map(_ + 1)
for { i <- myNums j <- 1 to i} yield i * jmyNums flatMap(i => 1 to i map (j => i * j))
![Page 23: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/23.jpg)
Parallel Collectionsscala> 1 to 1000000res0: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3,...
scala> res0.parres1: s.c.parallel.immutable.ParRange = ParRange(1, 2, 3,...
scala> res1 map(_ + 1)res2: s.c.parallel.immutable.ParSeq[Int] = ParVector(2, 3, 4,...
scala> res2.seqres3: s.c.immutable.Range = Range(2, 3, 4,...
• You can easily parallelize the application of a function literal to your collection by calling the par() method on a collection instance
• Uses JSR166 under the covers to fork/join for you• Use the seq() method on the parallel collection to return to a non-parallel
instance
![Page 24: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/24.jpg)
Partial Functions
• A simple match without the match keyword• The receive block in Akka actors is an excellent example• Is characterized by what "isDefinedAt" in the case
statements
class MyActor extends Actor { def receive = { case s: String => println("Got a String: " + s) case i: Int => println("Got an Int: " + i) case x => println("Got something else: " + x) }}
![Page 25: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/25.jpg)
Curryingdef product(i: Int)(j: Int) = i * j val doubler = product(2)_doubler(3) // Int = 6doubler(4) // Int = 8
val tripler = product(3)_tripler(4) // Int = 12tripler(5) // Int = 15
• Take a function that takes n parameters as separate argument lists• “Curry” it to create a new function that only takes one parameter• Fix on a value and use it to apply a specific implementation of a
product with semantic value• Have to be defined explicitly as such in Scala• The _ is what explicitly marks this as curried
![Page 26: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/26.jpg)
Actors
![Page 27: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/27.jpg)
Actorsimport akka.actor._
class MyActor extends Actor { def receive = { case x => println(“Got value: “ + x) }}
• Based on concepts from Erlang/OTP• Akka is replacing the core language actors• Concurrency paradigm using networks of
independent objects that only communicate via messaging and mailboxes
![Page 28: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/28.jpg)
Futures
![Page 29: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/29.jpg)
Futuresimport scala.concurrent._
val costInDollars = Future { webServiceProxy.getCostInDollars.mapTo[Int]}
costInDollars map (myPurchase.setCostInDollars(_))
• Allows you to write asynchronous code, which can be more performant than blocking
• Are not typed, hence the mapTo call above
![Page 30: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/30.jpg)
Futures in Sequenceval customerPurchases = for ( costUSD <- Future{ proxy.getCostInDollars.mapTo[Int]} totalPurchase <- Future{ proxy.addToTotal(costUSD).mapTo[Int]}} yield ((customerId -> totalPurchase))
• Scala’s for comprehensions allow you to compose higher-order functions, including Futures
• By sequencing the expressions on multiple lines, you can order dependencies
![Page 31: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/31.jpg)
Futures in Parallelval costUSD = Future{proxy.getCostInUSD(cost).mapTo[Int]}val costCAD = Future{proxy.getCostInCAD(cost).mapTo[Int]}val combinedCosts = for { cUSD <- costUSD cCAD <- costCAD} yield (cUSD, cCAD)
val costs = for ( (costUSD, costCAD) <- Future{proxy.getCostInUSD(cost).mapTo[Int]} zip Future{proxy.getCostInCAD(cost).mapTo[Int]}} yield (costUSD, costCAD)
• Define the futures separately and then compose• Alternatively, the zip method allows you to parallelize
futures execution within a for comprehension
![Page 32: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/32.jpg)
Implicits
![Page 33: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/33.jpg)
Implicit Conversions
![Page 34: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/34.jpg)
Implicit Conversionscase class Person(firstName: String, lastName: String)implicit def PersonToInt(p: Person) = p.toString.head.toInt
val me = Person("Jamie", "Allen")
val weird = 1 + me res0: Int = 81
• Looks for definitions at compile time that will satisfy type incompatibilities
• Modern IDEs will warn you with an underline when they are in use
• Limit scope as much as possible (see Josh Suereth's NE Scala 2011)
![Page 35: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/35.jpg)
Implicit Parametersdef executeFutureWithTimeout(f: Future)(implicit t: Timeout)
implicit val t: Timeout = Timeout(20, TimeUnit.MILLISECONDS)executeFutureWithTimeout(Future {proxy.getCustomer(id)})
• Allow you to define default parameter values that are only overridden if you do so explicitly
• Handy to avoid code duplication
![Page 36: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/36.jpg)
Implicit Classesimplicit class Person(name: String)
class Person(name: String)implicit final def Person(name: String): Person = new Person(name)
• New to Scala 2.10• Create extension methods to existing types• Desugars at compile time into a class
definition with an implicit conversion
![Page 37: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/37.jpg)
Type Theory
![Page 38: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/38.jpg)
Type Inference
• Declaring a variable/value• Return types of methods/functions• See Daniel Spiewak's Philly ETE 2011 talk• Good idea to show types on public interfaces• Specify types when you want to type certainty
![Page 39: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/39.jpg)
Type Classes I
• Allow you to layer in varying implementations of behavior without changing an existing inheritance structure
case class Customer(id: Long, firstName: String, lastName: String)
trait CustomerOrderById extends Ordering[Customer] { def compare(x: Customer, y: Customer): Int = { ... }}implicit object CustomerIdSort extends CustomerOrderById
val customers = List(Customer(1, "Jamie", "Allen"), Customer(5, "John", "Doe"), Customer(2, "Jane", "Smith"))val sortedCustomers = customers.sorted(CustomerIdSort)sortedCustomers: List[Customer] = List(Customer(1,Jamie,Allen), Customer(2,Jane,Smith), Customer(5,John,Doe))
![Page 40: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/40.jpg)
Type Classes II
• Allows you to generalize types that are acceptable parameters for methods
case class Dog(name: String)case class Ferret(name: String)case class Cat(name: String)abstract class OkayPets[T]object OkayPets { implicit object OkayDog extends OkayPets[Dog] implicit object OkayFerret extends OkayPets[Ferret]}def getPet[T](t: T)(implicit p: OkayPets[T]) = t
val myDog = getPet(Dog("Sparky")) // Worksval myCat = getPet(Cat("Sneezy")) // Fails at compile time
![Page 41: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/41.jpg)
Higher Kinded TypesMap[A, B] // Type constructor, not a type!
val myMap = Map[Int, String]() // Now it’s a type!
• Use other types to construct a new type• Also called type constructors
![Page 42: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/42.jpg)
Algebraic Data Typessealed abstract class DayOfTheWeekcase object Sunday extends DayOfTheWeekcase object Monday extends DayOfTheWeek ...case object Saturday extends DayOfTheWeek
val nextDay(d: DayOfTheWeek): DayOfTheWeek = d match { case Sunday => Monday case Monday => Tuesday ... case Saturday => Sunday }}
• Allow you to model the world in finite terms, such as enumerations, but also define behavior around them, with all of the power of case classes
• A finite number of possible subtypes, enforced by the "sealed" keyword (must be defined in the same source file)
![Page 43: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/43.jpg)
Macros
![Page 44: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/44.jpg)
Macros• New to Scala 2.10• Macros are used for generating code at
compile time, similar to LISP macros• Does not have compiler pragmas such as #ifdef
• Are implemented as "hygenic" macros at the point you call reify() – identifiers cannot be closed over in a macro definition
![Page 45: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/45.jpg)
ScalaLogging Macrodef debug(message: String): Unit = macro LoggerMacros.debugprivate object LoggerMacros { def debug(c: LoggerContext)(message: c.Expr[String]) = c.universe.reify( if (c.prefix.splice.underlying.isDebugEnabled) c.prefix.splice.underlying.debug(message.splice) )}
import com.typesafe.scalalogging.Loggingclass MyClass extends Logging { logger.debug("This won't occur if debug is not defined")}
• Existing log libraries allow us to define logging statements and then determine whether they result in output at runtime
• ScalaLogging allows a user to use a logging facility but decide at compile time whether or not to include the logging statement based on log level.
![Page 46: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/46.jpg)
Category Theory
![Page 47: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/47.jpg)
Category Theory
![Page 48: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/48.jpg)
Concepts and Arrowsval myIntToStringArrow: Int => String = _.toString
myIntToStringArrow(1100)res0: String = 1100
• Concepts are types• Arrows are functions that convert one concept
to another
![Page 49: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/49.jpg)
Morphismval number = 1000val numericString = number.toString
• Morphisms change one value in a category to another in the same category, from one type to another where types are the category
• Simplified, it converts a type with one property to a type with another property
• Must be pure, not side-effecting
![Page 50: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/50.jpg)
Functorval numbers = List(1, 2, 3, 4)val numericStrings = numbers.map(_.toString)
• Functors are transformations from one category to another that preserve morphisms
• Simplified, converts a type from one to another while maintaining the conversion of a type with one property to a type with another property
![Page 51: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/51.jpg)
Monadval customerPurchases = for ( costUSD <- proxy.getCostInDollars totalPurchase <- proxy.addToTotal(costUSD)} yield ((customerId -> totalPurchase))
• Very ephemeral concept• Must meet the laws of a monad to be one• Combine functor applications because they can be bound
together, sequencing operations on the underlying types• flatMap() is the method the Scala compiler uses to
bind monads
![Page 52: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/52.jpg)
Thank You!
![Page 53: Taxonomy of Scala](https://reader035.vdocuments.us/reader035/viewer/2022062512/554a5901b4c9054b328b4dbf/html5/thumbnails/53.jpg)
Credits• Sources
– Fast Track to Scala courseware by Typesafe– Scala in Depth, by Josh Suereth– DSLs in Action, Debasish Ghosh– Wikipedia– Runar Bjarnason's NE Scala 2011 talk– Daniel Sobral's blog– Brendan McAdams' blog
• Contributors– Dave Esterkin, Chariot Solutions– Josh Suereth, Typesafe