Scala for Java Developers - Intro

5,160 views
5,320 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
2 Comments
0 Likes
Statistics
Notes
  • 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

No Downloads
Views
Total views
5,160
On SlideShare
0
From Embeds
0
Number of Embeds
3,763
Actions
Shares
0
Downloads
70
Comments
2
Likes
0
Embeds 0
No embeds

No notes for slide

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

×