Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Scala
WTF is it? The new hotness or yet another functional fad?




                                                      ...
Scalable Language
 That’s why it’s pronounced Ska-Lah ?!??!




                                            2
Statically Typed



                   3
Runs on the JVM



                  4
Hybrid Language:
Object-Oriented + Functional


                               5
Why?



       6
Make Java more DRY



                     7
Allow easy creation of DSLs



                              8
Conciseness of Ruby +
Safety of Static Typing


                          9
No meta-programming but...
    very liberal syntax


                             10
11
12
13
14
15
16
Type Inference



                 17
List<String> oyVey = new ArrayList<String>();




                                                18
List<String> oyVey = new ArrayList<String>();
var hellsYeah = new ArrayList[String];




                                 ...
List<String> oyVey = new ArrayList<String>();
var hellsYeah = new ArrayList[String];
val booyah = 45; // it’s an Int




 ...
List<String> oyVey = new ArrayList<String>();
var hellsYeah = new ArrayList[String];
val booyah = 45; // it’s an Int
val d...
List<String> oyVey = new ArrayList<String>();
var hellsYeah = new ArrayList[String];
val booyah = 45; // it’s an Int
val d...
List<String> oyVey = new ArrayList<String>();
var hellsYeah = new ArrayList[String];
val booyah = 45; // it’s an Int
val d...
List<String> oyVey = new ArrayList<String>();
var hellsYeah = new ArrayList[String];
val booyah = 45; // it’s an Int
val d...
List<String> oyVey = new ArrayList<String>();
var hellsYeah = new ArrayList[String];
val booyah = 45; // it’s an Int
val d...
Liberal Syntax



                 26
val semicolons = “don’t need ‘em”
val but = “if it’s not clear”; val you = “need them”




                               ...
val semicolons = “don’t need ‘em”
val but = “if it’s not clear”; val you = “need them”

def braces(b:Boolean) =
  if (b)
 ...
val semicolons = “don’t need ‘em”
val but = “if it’s not clear”; val you = “need them”

def braces(b:Boolean) =
  if (b)
 ...
class Read(d:Date, val usage:Int) {
  def +(other:Int) = new Read(d,usage + other)
  override def toString = d + “:” + u

...
class Read(d:Date, val usage:Int) {
  def +(other:Int) = new Read(d,usage + other)
  override def toString = d + “:” + u

...
class Read(d:Date, val usage:Int) {
  def +(other:Int) = new Read(d,usage + other)
  override def toString = d + “:” + u

...
class Read(d:Date, val usage:Int) {
  def +(other:Int) = new Read(d,usage + other)
  override def toString = d + “:” + u
 ...
Mixins (Traits)



                  34
abstract class SaneCompare[T] {
  def <(other:T):Boolean
  def >(other:T) = !(this < other)
  def <=(other:T) = this == ot...
abstract class SaneCompare[T] {
  def <(other:T):Boolean
  def >(other:T) = !(this < other)
  def <=(other:T) = this == ot...
abstract class SaneCompare[T] {
  def <(other:T):Boolean
  def >(other:T) = !(this < other)
  def <=(other:T) = this == ot...
abstract class SaneCompare[T] {
  def <(other:T):Boolean
  def >(other:T) = !(this < other)
  def <=(other:T) = this == ot...
trait SaneCompare[T] {
  def <(other:T):Boolean
  def >(other:T) = !(this < other)
  def <=(other:T) = this == other || th...
Traits



•   Separate Concerns



                           40
Traits


•Separate Concerns
• Precedence is based on declaration order


                                             41
Traits

•Separate Concerns
• Precedence is based on declaration order
• All abstract – just like Java interface
• None abs...
Functions



            43
val reads = getSomeElectricReads // List[Read]

reads.sort( (a,b) => a.date.compareTo(b.date) < 0 )




                  ...
val reads = getSomeElectricReads // List[Read]

reads.sort( (a,b) => a.date.compareTo(b.date) < 0 )




                  ...
val reads = getSomeElectricReads // List[Read]

reads.sort( (a,b) => a.date.compareTo(b.date) < 0 )


      def sort(compF...
val reads = getSomeElectricReads // List[Read]

reads.sort( (a,b) => a.date.compareTo(b.date) < 0 )


      def sort(compF...
val reads = getSomeElectricReads // List[Read]

reads.sort( (a,b) => a.date.compareTo(b.date) < 0 )


      def sort(compF...
Methods are not Functions




                            49
Methods are not Functions
but can be passed as Functions


                                 50
List Processing



                  51
class State(val code:String,val desc:String)
val states = getAllStates

// returns a List[String] with the codes
states.ma...
Complete Access to JDK and Java
           libraries


                                  53
val s = new SingletonMetadataAwareAspectInstanceFactory()
val foo = s.getOrderForAspectClass(classOf[FooBar])




        ...
import java.util.Observer
import java.util.Observable

class AwesomeObserver extends Observer {
  def update(o:Observable,...
import java.util.Observer
import java.util.Observable

class AwesomeObserver extends Observer {
  def update(o:Observable,...
import java.util.Observer
import java.util.Observable

class AwesomeObserver extends Observer {
  def update(o:Observable,...
import java.util.Observer
import java.util.Observable

class AwesomeObserver extends Observer {
  def update(o:Observable,...
Goodbye Java’s Baggage



                         59
No primitives




                60
Proper F’ing Properties
class ServicePoint(val id:String,var name:String)

val sp = new ServicePoint(”foo”,”The Foo House”...
Proper F’ing Properties
class ServicePoint(val id:String,private var _name:String) {
  def name = _name.toUpperCase
  def ...
¡Adiós Checked Exceptions!
def readFile(f:File) = {
  val is = new FileInputStream(f)
  var ch = f.read
  while (ch != -1)...
¡Adiós Checked Exceptions!
def readFile(f:File) = {
  try {
    val is = new FileInputStream(f)
    var ch = f.read()
    ...
Can I get a closure?
class Logger(level:Int) {
  def debug(message: => String) = log(20,message)
  def info(message: => St...
Can I get a closure?
class Logger(level:Int) {
  def debug(message: => String) = log(20,message)
  def info(message: => St...
Can I get a closure?
class Logger(level:Int) {
  def debug(message: => String) = log(20,message)
  def info(message: => St...
Can I get a closure?
class Logger(level:Int) {
  def debug(message: => String) = log(20,message)
  def info(message: => St...
Can I get a closure?
class Logger(level:Int) {
  def debug(message: => String) = log(20,message)
  def info(message: => St...
“Literals”
val triStateArea = List(”MD”,”DC”,”VA”)
val theSouth = Map(”MD” -> true,”DC” -> false,
  ”VA” ->true)
val perlC...
“Literals”
val triStateArea = List(”MD”,”DC”,”VA”)
val theSouth = Map(”MD” -> true,”DC” -> false,
  ”VA” ->true)
val perlC...
“Literals”
val triStateArea = List(”MD”,”DC”,”VA”)
val theSouth = Map(”MD” -> true,”DC” -> false,
  ”VA” ->true)
val perlC...
“Literals”
class Read(val id:Int, val usage:Int, val age:Int)

object Read {
  def apply(id:Int,usage:Int,age:Int) =
    n...
“Literals”
class Read(val id:Int, val usage:Int, val age:Int)

object Read {
  def apply(id:Int,usage:Int,age:Int) =
    n...
Crazy Awesome - Pattern Matching
def fromEnglish(string:String) = string match {
  case “none” => 0
  case “one” => 1
  ca...
Crazy Awesome - Pattern Matching
def toUML(obj:Any) = obj match {
  case 0      => “0”
  case 1      => “0..1”
  case n:In...
Crazy Awesome - Pattern Matching
sealed abstract class Read
case class AMIRead(date:Date,usage:Int,duration:Int) extends R...
Crazy Awesome - Pattern Matching
sealed abstract class Read
case class AMIRead(date:Date,usage:Int,duration:Int) extends R...
Crazy Awesome - Pattern Matching
sealed abstract class Read
case class AMIRead(date:Date,usage:Int,duration:Int) extends R...
Crazy Awesome - Pattern Matching
sealed abstract class Read
case class AMIRead(date:Date,usage:Int,duration:Int) extends R...
Crazy Awesome - Pattern Matching
sealed abstract class Read
case class AMIRead(date:Date,usage:Int,duration:Int) extends R...
Crazy Awesome - Pattern Matching
sealed abstract class Read
case class AMIRead(date:Date,usage:Int,duration:Int) extends R...
Crazy Awesome - Implicits
sealed abstract class Read
case class AMIRead(date:Date,usage:Int,duration:Int) extends Read
cas...
Crazy Awesome - Implicits
sealed abstract class Read
case class AMIRead(date:Date,usage:Int,duration:Int) extends Read
cas...
Crazy Awesome - Implicits
sealed abstract class Read
case class AMIRead(date:Date,usage:Int,duration:Int) extends Read
cas...
Crazy Awesome - Implicits
sealed abstract class Read
case class AMIRead(date:Date,usage:Int,duration:Int) extends Read
cas...
Crazy Awesome - XML Literals
val xml = <html>
  <head>
    <title>Scala Pronunciation Guide</title>
  </head>
  <body>
   ...
Crazy Awesome - XML Literals
val lang = getLang
val title = translate(”scala.title”,lang)
val xml = <html lang={lang}>
  <...
Crazy Awesome - XML Literals
val lang = getLang
val title = translate(”scala.title”,lang)
val xml = <html lang={lang}>
  <...
Crazy Awesome - XML Literals
val states = List(”DC”,”MD”,”VA”)
val xml = <html>
  <body>
    <h1>States</h1>
    <ul>
    ...
Concurrency



              91
Message-passing




                  92
Message-passing
immutable objects



                    93
Message Passing
    Immutable objects
“actors” with “mailboxes”


                            94
case class Accumulate(amount: Int)
case class Reset
case class Total

object Accumulator extends Actor {
  def act = {
   ...
case class Accumulate(amount: Int)
case class Reset
case class Total

object Accumulator extends Actor {
  def act = {
   ...
case class Accumulate(amount: Int)
case class Reset
case class Total

object Accumulator extends Actor {
  def act = {
   ...
case class Accumulate(amount: Int)
case class Reset
case class Total

object Accumulator extends Actor {
  def act = {
   ...
case class Accumulate(amount: Int)
case class Reset
case class Total

object Accumulator extends Actor {
  def act = {
   ...
case class Accumulate(amount: Int)
case class Reset
case class Total

object Accumulator extends Actor {
  def act = {
   ...
case class Accumulate(amount: Int)
case class Reset
case class Total

object Accumulator extends Actor {
  def act = {
   ...
There’s a lot more to it



                           102
Demo




       103
Demo
Fill Gaps in Electric Meter Reads


                                    104
6/1     6/2     6/4     6/5     6/8
5 kwh   7 kwh   3 kwh   5 kwh   8 kwh




                                        105
6/1     6/2           6/4     6/5                 6/8
5 kwh   7 kwh         3 kwh   5 kwh               8 kwh
            ...
for all consecutive reads r1 and r2
  if r2 - r1 > one day
    fill gaps for (r1,r2)




                                  ...
fill:
 for all reads (first,second,List(rest))
    if gap(first,second)
      fill_gap(first,second) + fill(second + rest)
    e...
fill:
 for all reads (first,second,List(rest))
    if !first || !second
      reads
    else if gap(first,second)
      fill_ga...
def fillReads(
  strategy: (MeterRead,MeterRead) => Seq[MeterRead],
  reads:List[MeterRead]):List[MeterRead] =

  reads ma...
def fillReads(
  strategy: (MeterRead,MeterRead) => Seq[MeterRead],
  reads:List[MeterRead]):List[MeterRead] =

  reads ma...
def fillReads(
  strategy: (MeterRead,MeterRead) => Seq[MeterRead],
  reads:List[MeterRead]):List[MeterRead] =

  reads ma...
(demo with code)



                   113
It’s all happy flowers and meadows?




                                     114
It’s all happy flowers and meadows?
  not quite; a few stumbling blocks



                                      115
Generics, type-variance, etc. can
 get really confusing at times


                                    116
Library docs not as extensive as
             Java’s


                                   117
Still have to compile



                        118
Symbol Soup sometimes




                        119
Symbol Soup sometimes
  ...but it gets easier


                          120
Static typing sometimes paints you into
  a (very dark and confusing) corner



                                          ...
sometimes you just need
   method_missing



                          122
sometimes you just need
   monkey patching


                          123
Where is Scala now?



                      124
scala-lang.org



                 125
mailing lists, irc, a few blogs



                                  126
One good book, a few others



                              127
Online docs improving, but
        scattered


                             128
Spec is surprisingly readable



                                129
Java is on the decline




                         130
Java is on the decline
and Ruby and Python aren’t the
          only options


                                 131
questions?



             132
Upcoming SlideShare
Loading in …5
×

Scala for Java Developers - Intro

6,134 views

Published on

Slides of a talk I gave at work on Scala. It is geared toward Java developers. Some of the examples are in my company's domain, which is analyzing energy usage (i.e. a "read" is an electric meter read).

Published in: Technology, News & Politics
  • Slide 38: greater is (not (less OR equal))
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Great slides, but there are some minor problems.

    Slide 66. Parenthesis are required

    log.info(if (read.usage < 10) 'low read' else 'high read')

    Slide 83 does not compile
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Be the first to like this

Scala for Java Developers - Intro

  1. 1. Scala WTF is it? The new hotness or yet another functional fad? 1
  2. 2. Scalable Language That’s why it’s pronounced Ska-Lah ?!??! 2
  3. 3. Statically Typed 3
  4. 4. Runs on the JVM 4
  5. 5. Hybrid Language: Object-Oriented + Functional 5
  6. 6. Why? 6
  7. 7. Make Java more DRY 7
  8. 8. Allow easy creation of DSLs 8
  9. 9. Conciseness of Ruby + Safety of Static Typing 9
  10. 10. No meta-programming but... very liberal syntax 10
  11. 11. 11
  12. 12. 12
  13. 13. 13
  14. 14. 14
  15. 15. 15
  16. 16. 16
  17. 17. Type Inference 17
  18. 18. List<String> oyVey = new ArrayList<String>(); 18
  19. 19. List<String> oyVey = new ArrayList<String>(); var hellsYeah = new ArrayList[String]; 19
  20. 20. List<String> oyVey = new ArrayList<String>(); var hellsYeah = new ArrayList[String]; val booyah = 45; // it’s an Int 20
  21. 21. List<String> oyVey = new ArrayList<String>(); var hellsYeah = new ArrayList[String]; val booyah = 45; // it’s an Int val doh = booyah / 3; // not a Float!! 21
  22. 22. List<String> oyVey = new ArrayList<String>(); var hellsYeah = new ArrayList[String]; val booyah = 45; // it’s an Int val doh = booyah / 3; // not a Float!! val better:Float = booyah / 3; 22
  23. 23. List<String> oyVey = new ArrayList<String>(); var hellsYeah = new ArrayList[String]; val booyah = 45; // it’s an Int val doh = booyah / 3; // not a Float!! val better:Float = booyah / 3; // return type is java.lang.String def fullName = { first + “,” + last; } 23
  24. 24. List<String> oyVey = new ArrayList<String>(); var hellsYeah = new ArrayList[String]; val booyah = 45; // it’s an Int val doh = booyah / 3; // not a Float!! val better:Float = booyah / 3; // return type is java.lang.String def fullName = { first + “,” + last; } If the type seems obvious to you... 24
  25. 25. List<String> oyVey = new ArrayList<String>(); var hellsYeah = new ArrayList[String]; val booyah = 45; // it’s an Int val doh = booyah / 3; // not a Float!! val better:Float = booyah / 3; // return type is java.lang.String def fullName = { first + “,” + last; } If the type seems obvious to you... Scala can usually figure it out, too 25
  26. 26. Liberal Syntax 26
  27. 27. val semicolons = “don’t need ‘em” val but = “if it’s not clear”; val you = “need them” 27
  28. 28. val semicolons = “don’t need ‘em” val but = “if it’s not clear”; val you = “need them” def braces(b:Boolean) = if (b) “needed for multiple expressions” else “you don’t need them” 28
  29. 29. val semicolons = “don’t need ‘em” val but = “if it’s not clear”; val you = “need them” def braces(b:Boolean) = if (b) “needed for multiple expressions” else “you don’t need them” • if/else is a singular expression 29
  30. 30. class Read(d:Date, val usage:Int) { def +(other:Int) = new Read(d,usage + other) override def toString = d + “:” + u } 30
  31. 31. class Read(d:Date, val usage:Int) { def +(other:Int) = new Read(d,usage + other) override def toString = d + “:” + u } val f = new Read(new Date,10) val g = f + 20 31
  32. 32. class Read(d:Date, val usage:Int) { def +(other:Int) = new Read(d,usage + other) override def toString = d + “:” + u } val f = new Read(new Date,10) val g = f + 20 val gee = f.+(20) // yuck, but legal 32
  33. 33. class Read(d:Date, val usage:Int) { def +(other:Int) = new Read(d,usage + other) override def toString = d + “:” + u def later(ms:Int) = new Read(d + ms,usage) } val f = new Read(new Date,10) val g = f + 20 val gee = f.+(20) // yuck, but legal val l = f later (3600 * 1000) 33
  34. 34. Mixins (Traits) 34
  35. 35. abstract class SaneCompare[T] {   def <(other:T):Boolean   def >(other:T) = !(this < other)   def <=(other:T) = this == other || this < other   def >=(other:T) = this == other || this > other } class Read(d:Date,u:Int) extends SaneCompare[Read] {   val usage = u    def <(other:Read) = usage < other.usage } if (someRead >= someOtherRead) println(”finally!”) 35
  36. 36. abstract class SaneCompare[T] {   def <(other:T):Boolean   def >(other:T) = !(this < other)   def <=(other:T) = this == other || this < other   def >=(other:T) = this == other || this > other } class Read(d:Date,u:Int) extends AbstractEntity {   val usage = u    def <(other:Read) = usage < other.usage } // hmmm....what now? 36
  37. 37. abstract class SaneCompare[T] {   def <(other:T):Boolean   def >(other:T) = !(this < other)   def <=(other:T) = this == other || this < other   def >=(other:T) = this == other || this > other } class Read(d:Date,u:Int) extends AbstractEntity {   val usage = u    def <(other:Read) = usage < other.usage } // AbstractEntity extends SaneCompare? // God class above AbstractEntity subsumes it? 37
  38. 38. abstract class SaneCompare[T] {   def <(other:T):Boolean   def >(other:T) = !(this < other)   def <=(other:T) = this == other || this < other   def >=(other:T) = this == other || this > other } class Read(d:Date,u:Int) extends AbstractEntity {   val usage = u    def <(other:Read) = usage < other.usage } // AbstractEntity extends SaneCompare? // God class above AbstractEntity subsumes it? // these are different concepts entirely 38
  39. 39. trait SaneCompare[T] {   def <(other:T):Boolean   def >(other:T) = !(this < other)   def <=(other:T) = this == other || this < other   def >=(other:T) = this == other || this > other } class Read(d:Date,u:Int) extends AbstractEntity with SaneCompare[Read] {   val usage = u    def <(other:Read) = usage < other.usage } // now we have both! 39
  40. 40. Traits • Separate Concerns 40
  41. 41. Traits •Separate Concerns • Precedence is based on declaration order 41
  42. 42. Traits •Separate Concerns • Precedence is based on declaration order • All abstract – just like Java interface • None abstract – multiple inheritance 42
  43. 43. Functions 43
  44. 44. val reads = getSomeElectricReads // List[Read] reads.sort( (a,b) => a.date.compareTo(b.date) < 0 ) 44
  45. 45. val reads = getSomeElectricReads // List[Read] reads.sort( (a,b) => a.date.compareTo(b.date) < 0 ) 45
  46. 46. val reads = getSomeElectricReads // List[Read] reads.sort( (a,b) => a.date.compareTo(b.date) < 0 ) def sort(compFunc:(Read,Read) => Boolean) 46
  47. 47. val reads = getSomeElectricReads // List[Read] reads.sort( (a,b) => a.date.compareTo(b.date) < 0 ) def sort(compFunc:(Read,Read) => Boolean) Function2[Read,Read,Boolean] 47
  48. 48. val reads = getSomeElectricReads // List[Read] reads.sort( (a,b) => a.date.compareTo(b.date) < 0 ) def sort(compFunc:(Read,Read) => Boolean) Function2[Read,Read,Boolean] def sortReads(a:Read,b:Read) = a.date.compareTo(b.date) < 0 reads.sort(sortReads) // could also use a method // just keep in mind... 48
  49. 49. Methods are not Functions 49
  50. 50. Methods are not Functions but can be passed as Functions 50
  51. 51. List Processing 51
  52. 52. class State(val code:String,val desc:String) val states = getAllStates // returns a List[String] with the codes states.map( (state) => state.code ) // returns true if any state has a code of “DC” states.exists( (state) => state.code == “DC” ) // returns the state with the desc of “Hawaii” states.find( (state) => state.desc == “Hawaii” ) // returns a List[State] if states with descs matching states.filter( (state) => state.desc.startsWith(”V”) ) // Tons more 52
  53. 53. Complete Access to JDK and Java libraries 53
  54. 54. val s = new SingletonMetadataAwareAspectInstanceFactory() val foo = s.getOrderForAspectClass(classOf[FooBar]) 54
  55. 55. import java.util.Observer import java.util.Observable class AwesomeObserver extends Observer { def update(o:Observable, arg:Any) = if (o hasChanged) println(arg.asInstanceOf[MeterRead].date) } 55
  56. 56. import java.util.Observer import java.util.Observable class AwesomeObserver extends Observer { def update(o:Observable, arg:Any) = if (o hasChanged) println(arg.asInstanceOf[MeterRead].date) } 56
  57. 57. import java.util.Observer import java.util.Observable class AwesomeObserver extends Observer { def update(o:Observable, arg:Any) = if (o hasChanged) println(arg.asInstanceOf[MeterRead].date) } 57
  58. 58. import java.util.Observer import java.util.Observable class AwesomeObserver extends Observer { def update(o:Observable, arg:Any) = if (o hasChanged) println(arg.asInstanceOf[MeterRead].date) } 58
  59. 59. Goodbye Java’s Baggage 59
  60. 60. No primitives 60
  61. 61. Proper F’ing Properties class ServicePoint(val id:String,var name:String) val sp = new ServicePoint(”foo”,”The Foo House”) println(sp.id) // get, but no set println(sp.name) sp.name = “Thy Foo Haüs” 61
  62. 62. Proper F’ing Properties class ServicePoint(val id:String,private var _name:String) { def name = _name.toUpperCase def name_=(newName:String) = _name = newName } val sp = new ServicePoint(”foo”,”The Foo House”) sp.name = “Thy Foo Haüs” println(sp.name) // prints THY FOO HAÜS 62
  63. 63. ¡Adiós Checked Exceptions! def readFile(f:File) = { val is = new FileInputStream(f) var ch = f.read while (ch != -1) { print(ch) ch = f.read } } // Wow, that was clean! 63
  64. 64. ¡Adiós Checked Exceptions! def readFile(f:File) = { try { val is = new FileInputStream(f) var ch = f.read() while (ch != -1) { print(ch) ch = f.read } } catch { case fnfe:FileNotFoundException => println(f + ” not found, dude: ” + fnfe) } // All others bubble out, even if checked in Java } 64
  65. 65. Can I get a closure? class Logger(level:Int) { def debug(message: => String) = log(20,message) def info(message: => String) = log(10,message) def log(logLevel:Int, message: => String) = { if (level >= logLevel) println(message) } } val log = new Logger(10) log.debug(“Got read for “ + read.date + “ with usage “ + read.usage) read.usage = 44 log.info(if read.usage < 10 “low read” else “high read”) 65
  66. 66. Can I get a closure? class Logger(level:Int) { def debug(message: => String) = log(20,message) def info(message: => String) = log(10,message) def log(logLevel:Int, message: => String) = { if (level >= logLevel) println(message) } } val log = new Logger(10) log.debug(“Got read for “ + read.date + “ with usage “ + read.usage) read.usage = 44 log.info(if read.usage < 10 “low read” else “high read”) 66
  67. 67. Can I get a closure? class Logger(level:Int) { def debug(message: => String) = log(20,message) def info(message: => String) = log(10,message) def log(logLevel:Int, message: => String) = { if (level >= logLevel) println(message) } } val log = new Logger(10) log.debug(“Got read for “ + read.date + “ with usage “ + read.usage) read.usage = 44 log.info(if read.usage < 10 “low read” else “high read”) 67
  68. 68. Can I get a closure? class Logger(level:Int) { def debug(message: => String) = log(20,message) def info(message: => String) = log(10,message) def log(logLevel:Int, message: => String) = { if (level >= logLevel) println(message) } } val log = new Logger(10) log.debug(“Got read for “ + read.date + “ with usage “ + read.usage) read.usage = 44 log.info(if read.usage < 10 “low read” else “high read”) 68
  69. 69. Can I get a closure? class Logger(level:Int) { def debug(message: => String) = log(20,message) def info(message: => String) = log(10,message) def log(logLevel:Int, message: => String) = { if (level >= logLevel) println(message) } } val log = new Logger(10) log.debug(“Got read for “ + read.date + “ with usage “ + read.usage) read.usage = 44 log.info(if read.usage < 10 “low read” else “high read”) 69
  70. 70. “Literals” val triStateArea = List(”MD”,”DC”,”VA”) val theSouth = Map(”MD” -> true,”DC” -> false, ”VA” ->true) val perlCirca96 = (true,”Tuples rule”) val (hasTuples,message) = perlCirca96 70
  71. 71. “Literals” val triStateArea = List(”MD”,”DC”,”VA”) val theSouth = Map(”MD” -> true,”DC” -> false, ”VA” ->true) val perlCirca96 = (true,”Tuples rule”) val (hasTuples,message) = perlCirca96 These are actually API calls 71
  72. 72. “Literals” val triStateArea = List(”MD”,”DC”,”VA”) val theSouth = Map(”MD” -> true,”DC” -> false, ”VA” ->true) val perlCirca96 = (true,”Tuples rule”) val (hasTuples,message) = perlCirca96 This is done by the compiler creates a Tuple2[Boolean, String] 72
  73. 73. “Literals” class Read(val id:Int, val usage:Int, val age:Int) object Read { def apply(id:Int,usage:Int,age:Int) = new Read(id,usage,age) } val read = Read(4,10,33) 73
  74. 74. “Literals” class Read(val id:Int, val usage:Int, val age:Int) object Read { def apply(id:Int,usage:Int,age:Int) = new Read(id,usage,age) } val read = Read(4,10,33) // shortcut via compiler val read2 = Read.apply(4,10,33) 74
  75. 75. Crazy Awesome - Pattern Matching def fromEnglish(string:String) = string match { case “none” => 0 case “one” => 1 case _ => 2 } 75
  76. 76. Crazy Awesome - Pattern Matching def toUML(obj:Any) = obj match { case 0 => “0” case 1 => “0..1” case n:Int => “0..” + n case true => “1” case false => “0” case “many” => “0..*” case _ => “0..*” } 76
  77. 77. Crazy Awesome - Pattern Matching sealed abstract class Read case class AMIRead(date:Date,usage:Int,duration:Int) extends Read case class BillingRead(toDate:Date,usage:Int,numDays:Int,charges:Int) extends Read case class CorrectedRead(read:BillingRead, usage:Int) extends Read def proRate(read:Read) = read match { case AMIRead(d,usage,duration) => usage / duration case BillingRead(d,usage,days,c) => usage / days case CorrectedRead(BillingRead(d,oldUsage,days,c),usage) => (oldUsage + usage) / days } 77
  78. 78. Crazy Awesome - Pattern Matching sealed abstract class Read case class AMIRead(date:Date,usage:Int,duration:Int) extends Read case class BillingRead(toDate:Date,usage:Int,numDays:Int,charges:Int) extends Read case class CorrectedRead(read:BillingRead, usage:Int) extends Read def proRate(read:Read) = read match { case AMIRead(d,usage,duration) => usage / duration case BillingRead(d,usage,days,c) => usage / days case CorrectedRead(BillingRead(d,oldUsage,days,c),usage) => (oldUsage + usage) / days } • properties • equals/toString/hashCode • “extractor” • no need for “new” 78
  79. 79. Crazy Awesome - Pattern Matching sealed abstract class Read case class AMIRead(date:Date,usage:Int,duration:Int) extends Read case class BillingRead(toDate:Date,usage:Int,numDays:Int,charges:Int) extends Read case class CorrectedRead(read:BillingRead, usage:Int) extends Read def proRate(read:Read) = read match { case AMIRead(d,usage,duration) => usage / duration case BillingRead(d,usage,days,c) => usage / days case CorrectedRead(BillingRead(d,oldUsage,days,c),usage) => (oldUsage + usage) / days } 79
  80. 80. Crazy Awesome - Pattern Matching sealed abstract class Read case class AMIRead(date:Date,usage:Int,duration:Int) extends Read case class BillingRead(toDate:Date,usage:Int,numDays:Int,charges:Int) extends Read case class CorrectedRead(read:BillingRead, usage:Int) extends Read def proRate(read:Read) = read match { case AMIRead(d,usage,duration) => usage / duration case BillingRead(d,usage,days,c) => usage / days case CorrectedRead(BillingRead(d,oldUsage,days,c),usage) => (oldUsage + usage) / days } 80
  81. 81. Crazy Awesome - Pattern Matching sealed abstract class Read case class AMIRead(date:Date,usage:Int,duration:Int) extends Read case class BillingRead(toDate:Date,usage:Int,numDays:Int,charges:Int) extends Read case class CorrectedRead(read:BillingRead, usage:Int) extends Read def proRate(read:Read) = read match { case AMIRead(d,usage,duration) => usage / duration case BillingRead(d,usage,days,c) => usage / days case CorrectedRead(BillingRead(d,oldUsage,days,c),usage) => (oldUsage + usage) / days } 81
  82. 82. Crazy Awesome - Pattern Matching sealed abstract class Read case class AMIRead(date:Date,usage:Int,duration:Int) extends Read case class BillingRead(toDate:Date,usage:Int,numDays:Int,charges:Int) extends Read case class CorrectedRead(read:BillingRead, usage:Int) extends Read def proRate(read:Read) = read match { case AMIRead(d,usage,duration) => usage / duration case BillingRead(d,usage,days,c) => usage / days case CorrectedRead(BillingRead(d,oldUsage,days,c),usage) => (oldUsage + usage) / days } 82
  83. 83. Crazy Awesome - Implicits sealed abstract class Read case class AMIRead(date:Date,usage:Int,duration:Int) extends Read case class BillingRead(toDate:Date,usage:Int,numDays:Int,charges:Int) extends Read case class CorrectedRead(read:BillingRead, usage:Int) extends Read implicit def readToSeconds(r:Read):Int = r.date.getTime / 1000 def areConsecutive(from:Read, to:Read) = (from - to) <= from.duration 83
  84. 84. Crazy Awesome - Implicits sealed abstract class Read case class AMIRead(date:Date,usage:Int,duration:Int) extends Read case class BillingRead(toDate:Date,usage:Int,numDays:Int,charges:Int) extends Read case class CorrectedRead(read:BillingRead, usage:Int) extends Read implicit def readToSeconds(r:Read):Int = r.date.getTime / 1000 def areConsecutive(from:Read, to:Read) = (from - to) <= from.duration Have a Read, but need an Int 84
  85. 85. Crazy Awesome - Implicits sealed abstract class Read case class AMIRead(date:Date,usage:Int,duration:Int) extends Read case class BillingRead(toDate:Date,usage:Int,numDays:Int,charges:Int) extends Read case class CorrectedRead(read:BillingRead, usage:Int) extends Read implicit def readToSeconds(r:Read):Int = r.date.getTime / 1000 def areConsecutive(from:Read, to:Read) = (from - to) > from.duration Needs a Read and gives an Int 85
  86. 86. Crazy Awesome - Implicits sealed abstract class Read case class AMIRead(date:Date,usage:Int,duration:Int) extends Read case class BillingRead(toDate:Date,usage:Int,numDays:Int,charges:Int) extends Read case class CorrectedRead(read:BillingRead, usage:Int) extends Read implicit def readToSeconds(r:Read):Int = r.date.getTime / 1000 def areConsecutive(from:Read, to:Read) = (from - to) > from.duration • Given this and matching, casting is rarely needed 86
  87. 87. Crazy Awesome - XML Literals val xml = <html> <head> <title>Scala Pronunciation Guide</title> </head> <body> <h1>How to Pronounce It</h1> </body> </html> println(xml) 87
  88. 88. Crazy Awesome - XML Literals val lang = getLang val title = translate(”scala.title”,lang) val xml = <html lang={lang}> <head> <title>{title}</title> </head> <body> <h1>{title.toUpperCase}</h1> </body> </html> println(xml) 88
  89. 89. Crazy Awesome - XML Literals val lang = getLang val title = translate(”scala.title”,lang) val xml = <html lang={lang}> <head> <title>{title}</title> </head> <body> <h1>{title.toUpperCase}</h1> </body> </html> println(xml) 89
  90. 90. Crazy Awesome - XML Literals val states = List(”DC”,”MD”,”VA”) val xml = <html> <body> <h1>States</h1> <ul> { states.map( (state) => <li>{state}</li> ) } </ul> </body> </html> println(xml) 90
  91. 91. Concurrency 91
  92. 92. Message-passing 92
  93. 93. Message-passing immutable objects 93
  94. 94. Message Passing Immutable objects “actors” with “mailboxes” 94
  95. 95. case class Accumulate(amount: Int) case class Reset case class Total object Accumulator extends Actor { def act = { var sum = 0 loop { react { case Accumulate(n) => sum += n case Reset => sum = 0 case Total => reply(sum); exit } } } } object Accumulators extends Application { Accumulator.start for(i <- (1 to 100)) { Accumulator ! Accumulate(i) } Accumulator !? Total match { case result: Int => println(result) } } 95
  96. 96. case class Accumulate(amount: Int) case class Reset case class Total object Accumulator extends Actor { def act = { var sum = 0 loop { react { case Accumulate(n) => sum += n case Reset => sum = 0 case Total => reply(sum); exit } } } } object Accumulators extends Application { Accumulator.start for(i <- (1 to 100)) { Accumulator ! Accumulate(i) } Accumulator !? Total match { case result: Int => println(result) } } 96
  97. 97. case class Accumulate(amount: Int) case class Reset case class Total object Accumulator extends Actor { def act = { var sum = 0 loop { react { case Accumulate(n) => sum += n case Reset => sum = 0 case Total => reply(sum); exit } } } } object Accumulators extends Application { Accumulator.start for(i <- (1 to 100)) { Accumulator ! Accumulate(i) } Accumulator !? Total match { case result: Int => println(result) } } 97
  98. 98. case class Accumulate(amount: Int) case class Reset case class Total object Accumulator extends Actor { def act = { var sum = 0 loop { react { case Accumulate(n) => sum += n case Reset => sum = 0 case Total => reply(sum); exit } } } } object Accumulators extends Application { Accumulator.start for(i <- (1 to 100)) { Accumulator ! Accumulate(i) } Accumulator !? Total match { case result: Int => println(result) } } 98
  99. 99. case class Accumulate(amount: Int) case class Reset case class Total object Accumulator extends Actor { def act = { var sum = 0 loop { react { case Accumulate(n) => sum += n case Reset => sum = 0 case Total => reply(sum); exit } } } } object Accumulators extends Application { Accumulator.start for(i <- (1 to 100)) { Accumulator ! Accumulate(i) } Accumulator !? Total match { case result: Int => println(result) } } 99
  100. 100. case class Accumulate(amount: Int) case class Reset case class Total object Accumulator extends Actor { def act = { var sum = 0 loop { react { case Accumulate(n) => sum += n case Reset => sum = 0 case Total => reply(sum); exit } } } } object Accumulators extends Application { Accumulator.start for(i <- (1 to 100)) { Accumulator ! Accumulate(i) } Accumulator !? Total match { case result: Int => println(result) } } 100
  101. 101. case class Accumulate(amount: Int) case class Reset case class Total object Accumulator extends Actor { def act = { var sum = 0 loop { react { case Accumulate(n) => sum += n case Reset => sum = 0 case Total => reply(sum); exit } } } } object Accumulators extends Application { Accumulator.start for(i <- (1 to 100)) { Accumulator ! Accumulate(i) } Accumulator !? Total match { case result: Int => println(result) } } 101
  102. 102. There’s a lot more to it 102
  103. 103. Demo 103
  104. 104. Demo Fill Gaps in Electric Meter Reads 104
  105. 105. 6/1 6/2 6/4 6/5 6/8 5 kwh 7 kwh 3 kwh 5 kwh 8 kwh 105
  106. 106. 6/1 6/2 6/4 6/5 6/8 5 kwh 7 kwh 3 kwh 5 kwh 8 kwh 6/3 6/6 6/7 ?? ?? ?? 106
  107. 107. for all consecutive reads r1 and r2 if r2 - r1 > one day fill gaps for (r1,r2) 107
  108. 108. fill: for all reads (first,second,List(rest)) if gap(first,second) fill_gap(first,second) + fill(second + rest) else first + fill(second + rest) 108
  109. 109. fill: for all reads (first,second,List(rest)) if !first || !second reads else if gap(first,second) fill_gap(first,second) + fill(second + rest) else first + fill(second + rest) 109
  110. 110. def fillReads( strategy: (MeterRead,MeterRead) => Seq[MeterRead], reads:List[MeterRead]):List[MeterRead] = reads match { case List() => List() case first :: List() => List(first) case first :: second :: rest if gap(first, second) => first :: strategy(x,y).toList ::: fillReads(strategy, second :: rest) case first :: rest => first :: fillReads(strategy,rest) } 110
  111. 111. def fillReads( strategy: (MeterRead,MeterRead) => Seq[MeterRead], reads:List[MeterRead]):List[MeterRead] = reads match { case List() => List() case first :: List() => List(first) case first :: second :: rest if gap(first, second) => first :: strategy(x,y).toList ::: fillReads(strategy, second :: rest) case first :: rest => first :: fillReads(strategy,rest) } 111
  112. 112. def fillReads( strategy: (MeterRead,MeterRead) => Seq[MeterRead], reads:List[MeterRead]):List[MeterRead] = reads match { case List() => List() case first :: List() => List(first) case first :: second :: rest if gap(first, second) => first :: strategy(x,y).toList ::: fillReads(strategy, second :: rest) case first :: rest => first :: fillReads(strategy,rest) } 112
  113. 113. (demo with code) 113
  114. 114. It’s all happy flowers and meadows? 114
  115. 115. It’s all happy flowers and meadows? not quite; a few stumbling blocks 115
  116. 116. Generics, type-variance, etc. can get really confusing at times 116
  117. 117. Library docs not as extensive as Java’s 117
  118. 118. Still have to compile 118
  119. 119. Symbol Soup sometimes 119
  120. 120. Symbol Soup sometimes ...but it gets easier 120
  121. 121. Static typing sometimes paints you into a (very dark and confusing) corner 121
  122. 122. sometimes you just need method_missing 122
  123. 123. sometimes you just need monkey patching 123
  124. 124. Where is Scala now? 124
  125. 125. scala-lang.org 125
  126. 126. mailing lists, irc, a few blogs 126
  127. 127. One good book, a few others 127
  128. 128. Online docs improving, but scattered 128
  129. 129. Spec is surprisingly readable 129
  130. 130. Java is on the decline 130
  131. 131. Java is on the decline and Ruby and Python aren’t the only options 131
  132. 132. questions? 132

×