Scala for Java Developers - Intro

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

0 comments

Post a comment

    Post a comment
    Embed Video
    Edit your comment Cancel

    Favorites, Groups & Events

    Scala for Java Developers - Intro - Presentation Transcript

    1. Scala WTF is it? The new hotness or yet another functional fad? 1
    2. Scalable Language That’s why it’s pronounced Ska-Lah ?!??! 2
    3. Statically Typed 3
    4. Runs on the JVM 4
    5. Hybrid Language: Object-Oriented + Functional 5
    6. Why? 6
    7. Make Java more DRY 7
    8. Allow easy creation of DSLs 8
    9. Conciseness of Ruby + Safety of Static Typing 9
    10. No meta-programming but... very liberal syntax 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. Type Inference 17
    18. List<String> oyVey = new ArrayList<String>(); 18
    19. List<String> oyVey = new ArrayList<String>(); var hellsYeah = new ArrayList[String]; 19
    20. List<String> oyVey = new ArrayList<String>(); var hellsYeah = new ArrayList[String]; val booyah = 45; // it’s an Int 20
    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. 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. 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. 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. 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. Liberal Syntax 26
    27. val semicolons = “don’t need ‘em” val but = “if it’s not clear”; val you = “need them” 27
    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. 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. class Read(d:Date, val usage:Int) { def +(other:Int) = new Read(d,usage + other) override def toString = d + “:” + u } 30
    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. 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. 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. Mixins (Traits) 34
    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. 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. 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. 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. 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. Traits • Separate Concerns 40
    41. Traits •Separate Concerns • Precedence is based on declaration order 41
    42. Traits •Separate Concerns • Precedence is based on declaration order • All abstract – just like Java interface • None abstract – multiple inheritance 42
    43. Functions 43
    44. val reads = getSomeElectricReads // List[Read] reads.sort( (a,b) => a.date.compareTo(b.date) < 0 ) 44
    45. val reads = getSomeElectricReads // List[Read] reads.sort( (a,b) => a.date.compareTo(b.date) < 0 ) 45
    46. val reads = getSomeElectricReads // List[Read] reads.sort( (a,b) => a.date.compareTo(b.date) < 0 ) def sort(compFunc:(Read,Read) => Boolean) 46
    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. 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. Methods are not Functions 49
    50. Methods are not Functions but can be passed as Functions 50
    51. List Processing 51
    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. Complete Access to JDK and Java libraries 53
    54. val s = new SingletonMetadataAwareAspectInstanceFactory() val foo = s.getOrderForAspectClass(classOf[FooBar]) 54
    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. 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. 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. 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. Goodbye Java’s Baggage 59
    60. No primitives 60
    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. 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. ¡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. ¡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. 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. 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. 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. 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. 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. “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. “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. “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. “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. “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. Crazy Awesome - Pattern Matching def fromEnglish(string:String) = string match { case “none” => 0 case “one” => 1 case _ => 2 } 75
    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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. Concurrency 91
    92. Message-passing 92
    93. Message-passing immutable objects 93
    94. Message Passing Immutable objects “actors” with “mailboxes” 94
    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. 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. 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. 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. 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. 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. 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. There’s a lot more to it 102
    103. Demo 103
    104. Demo Fill Gaps in Electric Meter Reads 104
    105. 6/1 6/2 6/4 6/5 6/8 5 kwh 7 kwh 3 kwh 5 kwh 8 kwh 105
    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. for all consecutive reads r1 and r2 if r2 - r1 > one day fill gaps for (r1,r2) 107
    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. 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. 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. 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. 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. (demo with code) 113
    114. It’s all happy flowers and meadows? 114
    115. It’s all happy flowers and meadows? not quite; a few stumbling blocks 115
    116. Generics, type-variance, etc. can get really confusing at times 116
    117. Library docs not as extensive as Java’s 117
    118. Still have to compile 118
    119. Symbol Soup sometimes 119
    120. Symbol Soup sometimes ...but it gets easier 120
    121. Static typing sometimes paints you into a (very dark and confusing) corner 121
    122. sometimes you just need method_missing 122
    123. sometimes you just need monkey patching 123
    124. Where is Scala now? 124
    125. scala-lang.org 125
    126. mailing lists, irc, a few blogs 126
    127. One good book, a few others 127
    128. Online docs improving, but scattered 128
    129. Spec is surprisingly readable 129
    130. Java is on the decline 130
    131. Java is on the decline and Ruby and Python aren’t the only options 131
    132. questions? 132
    SlideShare Zeitgeist 2009

    + David CopelandDavid Copeland Nominate

    custom

    396 views, 0 favs, 3 embeds more stats

    Slides of a talk I gave at work on Scala. It is ge more

    More info about this document

    CC Attribution License

    Go to text version

    • Total Views 396
      • 231 on SlideShare
      • 165 from embeds
    • Comments 0
    • Favorites 0
    • Downloads 20
    Most viewed embeds
    • 163 views on http://www.naildrivin5.com
    • 1 views on http://xn--dfi5d.ws
    • 1 views on http://naildrivin5.com

    more

    All embeds
    • 163 views on http://www.naildrivin5.com
    • 1 views on http://xn--dfi5d.ws
    • 1 views on http://naildrivin5.com

    less

    Flagged as inappropriate Flag as inappropriate
    Flag as inappropriate

    Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

    Cancel
    File a copyright complaint
    Having problems? Go to our helpdesk?

    Categories