Effective Scala (JavaDay Riga 2013)

  • 759 views
Uploaded on

 

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
759
On Slideshare
0
From Embeds
0
Number of Embeds
3

Actions

Shares
Downloads
21
Comments
0
Likes
4

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Effective Scala Javaday Riga 2013 @mircodotta
  • 2. Golden rule? mple! IT Si KEEP
  • 3. not because you It is at you should can, th
  • 4. What’s this talk about? mize your use of Opti ala to solve real Sc world problems t explosions, withou broken thumbs or bullet wounds
  • 5. Agenda • Mantras • Collection-foo • Implicits • Style matters
  • 6. Style matters
  • 7. Learn the Scala way You know it when you got it Scala ain’t Java nor Ruby nor Haskell nor <INSERT known PL> http://docs.scala-lang.org/style/
  • 8. Abstract members trait Shape { val edges: Int } Why? class Triangle extends Shape { override def edges: Int = 3 } Because this doesn’t compile!
  • 9. Abstract members Always use def for abstract members! trait Shape { def edges: Int }
  • 10. You’ve to override trait Worker { def run(): Unit } abstract class MyWorker extends Worker { override def run(): Unit = //... }
  • 11. Don’t leak your types! trait Logger { def log(m: String): Unit } object Logger { class StdLogger extends Logger { override def log(m: String): Unit = println(m) } def apply = new StdLogger() } What’s the return type here?
  • 12. Hide your secrets object SauceFactory { def makeSecretSauce(): Sauce = { val ingredients = getMagicIngredients() val formula = getSecretFormula() SauceMaker.prepare(ingredients, formula) } te! getMagicIngredients(): iva pr def Ingredients = //... def getSecretFormula(): Formula = //... }
  • 13. Visibility modifiers • Scala has very expressive visibility modifiers • Access modifiers can be augmented with qualifiers Did you know that... public (default) package protected private private nested packages have access to private classes • Companion object/classes have access to each other private members! private[pkg] protected • everything you have in java, and much more
  • 14. Don’t blow up the stack! IF YOU THINK IT’S tailrecursive, SAY so! case class Node(value: Int, edges: List[Node]) def bfs(node: Node, pred: Node => Boolean): Option[Node] = { @scala.annotation.tailrec def search(acc: List[Node]): Option[Node] = acc match { case Nil => None case x :: xs => if (pred(x)) Some(x) else search(xs ::: xs.edges) } search(List(node)) }
  • 15. String interpolation case class Complex(real: Int, im: Int) { override def toString: String = real + " + " + im + "i" } case class Complex(real: Int, im: Int) { override def toString: String = s"$real + ${im}i" } interpolator!
  • 16. Mantras Mantras
  • 17. Use the REPL
  • 18. Or the Worksheet ;-)
  • 19. Write Expressions, not Statements
  • 20. Expressions! • shorter • simpler • Composable!
  • 21. def home(): HttpPage = { var page: HttpPage = null try page = prepareHttpPage() catch { case _: TimeoutEx => page = TimeoutPage case _: Exception => page = NoPage } return page } def home(): HttpPage = try prepareHttpPage() catch { case _: TimeoutEx => TimeoutPage case _: Exception => NoPage }
  • 22. Expressions compose! def home(): HttpPage = try prepareHttpPage() catch { case _: TimeoutEx => TimeoutPage case _: Exception => NoPage } Try..catch is an expression This is a PartialFunction[Throwable,HttpPage] def timeoutCatch = { case _: TimeoutEx => TimeoutPage } def noPageCatch = { case _: Exception => NoPage } def home(): HttpPage = try prepareHttpPage() catch timeoutCatch orElse noPageCatch mp co e! os
  • 23. return is overrated • superfluous •avoid multiple exit point •Can impact performance!
  • 24. How is this compiled? @volatile var isInterrupted: Boolean = false def process(files: Vector[File]): Unit = { files foreach { file => if(isInterrupted) return process(file) } logger.debug(s"processed ${files.size}") }
  • 25. def process(files: Vector[File]): Unit = { files foreach { file => if(isInterrupted) return process(file) } logger.debug(s"processed ${files.size}") } scalac A.scala -Xprint:uncurry def process(files: List[File]): Unit = { try { files.foreach { file => if (isInterrupted) throw new NonLocalReturnControl(nonLocalReturnKey1, value = ()) process(file) } logger.debug("processed “ + files.size) } catch { case ex: NonLocalReturnControl => if (ex.key.eq(nonLocalReturnKey1)) ex.value else throw ex } }
  • 26. Don’t use null
  • 27. null is a disease • nullcheks will spread • code is brittle • NPE will still happen • assertions won’t help
  • 28. Forget null, use Option • no more “it may be null” • type-safe • documentation
  • 29. def authenticate(session: HttpSession, username: Option[String], password: Option[String]) = for { user <- username pass <- password if canAuthenticate(user,pass) privileges <- privilegesFor(user) } yield inject(session, privileges)
  • 30. But don’t overuse Option a null-object may be a much better fit def home(): HttpPage = try prepareHttpPage() catch { case _: TimeoutEx => TimeoutPage case _: Exception => NoPage } Null Object!
  • 31. Stay immutable
  • 32. Immutability 3 reasons why it matters? • Simplifies reasoning • simplifies reasoning • simplifies reasoning
  • 33. Immutability Allows co/contra variance ity il tab e mu anc -ari ---+v ------les ub Tro Jav a String[] a = {""}; Object[] b = a; b[0] = 1; String value = a[0]; ayStoreException java.lang.Arr
  • 34. Immutability • correct equals & hashcode! • it also simplifies reasoning about concurrency • thread-safe by design
  • 35. Immutability • Mutability is still ok, but keep it in local scopes • api methods should return immutable objects
  • 36. Do you want faster Scala compilation? program to an interface, not an implementation.
  • 37. Collection-foo Collection-foo
  • 38. http://www.scala-lang.org/docu/files/collections-api/collections.html
  • 39. Learn the API !=, ##, ++, ++:, +:, /:, /:, :+, ::, :::, :, <init>, ==, addString, aggregate, andThen, apply, applyOrElse, asInstanceOf, canEqual, collect, collectFirst, combinations, companion, compose, contains, containsSlice, copyToArray, copyToBuffer, corresponds, count, diff, distinct, drop, dropRight, dropWhile, endsWith, eq, equals, exists, filter, filterNot, find, flatMap, flatten, fold, foldLeft, foldRight, forall, foreach, genericBuilder, getClass, groupBy, grouped, hasDefiniteSize, hashCode, head, headOption, indexOf, indexOfSlice, indexWhere, indices, init, inits, intersect, isDefinedAt, isEmpty, isInstanceOf, isTraversableAgain, iterator, last, lastIndexOf, lastIndexOfSlice, lastIndexWhere, lastOption, length, lengthCompare, lift, map, mapConserve, max, maxBy, min, minBy, mkString, ne, nonEmpty, notify, notifyAll, orElse, padTo, par, partition, patch, permutations, prefixLength, product, productArity, productElement, productIterator, productPrefix, reduce, reduceLeft, reduceLeftOption, reduceOption, reduceRight, reduceRightOption, removeDuplicates, repr, reverse, reverseIterator, reverseMap, reverse_:::, runWith, sameElements, scan, scanLeft, scanRight, segmentLength, seq, size, slice, sliding, sortBy, sortWith, sorted, span, splitAt, startsWith, stringPrefix, sum, synchronized, tail, tails, take, takeRight, takeWhile, to, toArray, toBuffer, toIndexedSeq, toIterable, toIterator, toList, toMap, toSeq, toSet, toStream, toString, toTraversable, toVector, transpose, union, unzip, unzip3, updated, view, wait, withFilter, zip, zipAll, zipWithIndex
  • 40. Know when to breakOut def adultFriends(p: Person): Array[Person] = { val adults = // <- of type List for { friend <- p.friends // <- of type List if friend.age >= 18 } yield friend adults.toArray } can we avoid the 2nd iteration? def adultFriends(p: Person): Array[Person] = (for { friend <- p.friends if friend.age >= 18 } yield friend)(collection.breakOut)
  • 41. Common pitfall def pick(users: Seq[User]) mutable or immutable? Good question! remedy import scala.collection.immutable def pick(users: immutable.Seq[User])
  • 42. Implicits
  • 43. Limit the scope of implicits
  • 44. Implicit Resolution • implicits in the local scope • • • Implicits defined in current scope (1) explicit imports (2) wildcard imports (3) • parts of A type • • • companion object of the type (and inherited types) companion objects of type arguments of the type outer objects for nested types http://www.scala-lang.org/docu/files/ScalaReference.pdf
  • 45. Implicit Scope (Parts) trait Logger { def log(m: String): Unit } object Logger { implicit object StdLogger extends Logger { override def log(m: String): Unit = println(m) } def log(m: String)(implicit l: Logger) = l.log(m) } Logger.log("Hello") // But I can override the default! Logger.log("Hello")(RemoteLogger)
  • 46. avoid implicit views
  • 47. Typeclass pattern trait Serializer[T] { def ser(in: T): String } object Serializer { def ser[T](in: T)(implicit ev: Serializer[T]) = ev.ser(in) implicit object IntSer extends Serializer[Int] { def ser(in: Int): String = s"int:$in" } // provide implicits for common lib types... } Serializer.ser(2) //> res0: String = int:2
  • 48. Typeclass - typesafe case class Person(firstName: String, lastName: String) val p = Person("Mirco", "Dotta") Serializer.ser(p) could not find implicit value for parameter ev: Serializer[Person]
  • 49. Typeclass - typesafe case class Person(firstName: String, lastName: String) object Person { implicit object PersSer extends Serializer[Person] { def ser(in: Person) = s"person:${in.firstName},${in.lastName}" } } val p = Person("Mirco", "Dotta") Serializer.ser(p) > res0: String = person:Mirco,Dotta
  • 50. Typeclass -extensible Serializer.ser(2) //> res0: String = int:2 implicit object BinarySer extends Serializer[Int] { def ser(in: Int): String = in.toBinaryString } Serializer.ser(2) > res1: String = 10
  • 51. Typeclass Pros & Cons + alternative to inheritance • • • extend classes you don’t control single responsibility principle modularization/decoupling + overridable at call site + binary compatibility - decoupling - advanced concept
  • 52. Looking ahead
  • 53. Level up! Scala In Depth Joshua Suereth http://www.manning.com/suereth/
  • 54. Effective Scala @mircodotta Thanks to @jsuereth for a good portion of the slides’ content, and @heathermiller for the presentation style