Effective Scala (JavaDay Riga 2013)

56
Effective Scala @mircodotta Javaday Riga 2013

description

 

Transcript of Effective Scala (JavaDay Riga 2013)

Page 1: Effective Scala (JavaDay Riga 2013)

Effective Scala @mircodotta

Javaday Riga 2013

Page 2: Effective Scala (JavaDay Riga 2013)

KEEP IT Simple!

Golden rule?

Page 3: Effective Scala (JavaDay Riga 2013)
Page 4: Effective Scala (JavaDay Riga 2013)

It is not because you

can, that you should

Page 5: Effective Scala (JavaDay Riga 2013)
Page 6: Effective Scala (JavaDay Riga 2013)

Optimize your use of

Scala to solve real

world problems without explosions,

broken thumbs or bullet wounds

What’s this talk about?

Page 7: Effective Scala (JavaDay Riga 2013)

Agenda•Style matters

•Mantras

•Collection-foo

•Implicits

Page 8: Effective Scala (JavaDay Riga 2013)

Style matters

Page 9: Effective Scala (JavaDay Riga 2013)

Learn the Scala wayYou know it when you got it

Scala ain’t Javanor Ruby

nor Haskellnor <INSERT known PL>

http://docs.scala-lang.org/style/

Page 10: Effective Scala (JavaDay Riga 2013)

Abstract memberstrait Shape { val edges: Int}

class Triangle extends Shape { override def edges: Int = 3}

Why?

Because this doesn’t compile!

Page 11: Effective Scala (JavaDay Riga 2013)

Abstract members

trait Shape { def edges: Int}

Always use def for abstract members!

Page 12: Effective Scala (JavaDay Riga 2013)

You’ve to overridetrait Worker { def run(): Unit}

abstract class MyWorker extends Worker { override def run(): Unit = //...}

Page 13: Effective Scala (JavaDay Riga 2013)

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?

Page 14: Effective Scala (JavaDay Riga 2013)

Hide your secretsobject SauceFactory { def makeSecretSauce(): Sauce = { val ingredients = getMagicIngredients() val formula = getSecretFormula() SauceMaker.prepare(ingredients, formula) } def getMagicIngredients(): Ingredients = //... def getSecretFormula(): Formula = //...}

private!

Page 15: Effective Scala (JavaDay Riga 2013)

Visibility modifiers

public (default)

package private[pkg]protected protected

private private

• Scala has very expressive visibility modifiers

• Access modifiers can be augmented with qualifiers

• nested packages have access to private classes

• Companion object/classes have access to each other private members!

everything you have in java, and much more

Did you know that...

Page 16: Effective Scala (JavaDay Riga 2013)

Don’t blow up the stack!

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))}

IF YOU THINK IT’S tailrecursive, SAY so!

Page 17: Effective Scala (JavaDay Riga 2013)

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!

Page 18: Effective Scala (JavaDay Riga 2013)

MantrasMantras

Page 19: Effective Scala (JavaDay Riga 2013)

Use the REPL

Page 20: Effective Scala (JavaDay Riga 2013)

Or the Worksheet ;-)

Page 21: Effective Scala (JavaDay Riga 2013)

Write Expressions, not Statements

Page 22: Effective Scala (JavaDay Riga 2013)

Expressions!

•shorter

•simpler

•Composable!

Page 23: Effective Scala (JavaDay Riga 2013)

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 }

Page 24: Effective Scala (JavaDay Riga 2013)

Expressions compose!def home(): HttpPage = try prepareHttpPage() catch { case _: TimeoutEx => TimeoutPage case _: Exception => NoPage }

Try..catch isan expression

This is a PartialFunction[Throwable,HttpPage]

def home(): HttpPage = try prepareHttpPage() catch timeoutCatch orElse noPageCatch

def timeoutCatch = { case _: TimeoutEx => TimeoutPage}def noPageCatch = { case _: Exception => NoPage} compose

!

Page 25: Effective Scala (JavaDay Riga 2013)

return is overrated

•superfluous

•avoid multiple exit point

•Can impact performance!

Page 26: Effective Scala (JavaDay Riga 2013)

@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}")}

How is this compiled?

Page 27: Effective Scala (JavaDay Riga 2013)

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 }}

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

Page 28: Effective Scala (JavaDay Riga 2013)

Don’t use null

Page 29: Effective Scala (JavaDay Riga 2013)

null is a disease

•nullcheks will spread

•code is brittle

•NPE will still happen

•assertions won’t help

Page 30: Effective Scala (JavaDay Riga 2013)

Forget null, use Option

•no more “it may be null”

•type-safe

•documentation

Page 31: Effective Scala (JavaDay Riga 2013)

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)

Page 32: Effective Scala (JavaDay Riga 2013)

But don’t overuse Optiona null-object may be a much

better fit

def home(): HttpPage = try prepareHttpPage() catch { case _: TimeoutEx => TimeoutPage case _: Exception => NoPage }

Null Object!

Page 33: Effective Scala (JavaDay Riga 2013)

Stay immutable

Page 34: Effective Scala (JavaDay Riga 2013)

Immutability

•Simplifies reasoning

•simplifies reasoning

•simplifies reasoning

3 reasons why it matters?

Page 35: Effective Scala (JavaDay Riga 2013)

ImmutabilityAllows co/contra variance

String[] a = {""};Object[] b = a;b[0] = 1;String value = a[0];

mutability

+ variance

----------------

Troubles

Java

java.lang.ArrayStoreException

Page 36: Effective Scala (JavaDay Riga 2013)

Immutability

•correct equals & hashcode!

• it also simplifies reasoning about concurrency

•thread-safe by design

Page 37: Effective Scala (JavaDay Riga 2013)

Immutability

•Mutability is still ok, but keep it in local scopes

•api methods should return immutable objects

Page 38: Effective Scala (JavaDay Riga 2013)

program to an interface, not an implementation.

Do you want faster Scala compilation?

Page 39: Effective Scala (JavaDay Riga 2013)

Collection-foo

Collection-foo

Page 41: Effective Scala (JavaDay Riga 2013)

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

Page 42: Effective Scala (JavaDay Riga 2013)

Know when to breakOutdef 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}

def adultFriends(p: Person): Array[Person] = (for { friend <- p.friends if friend.age >= 18 } yield friend)(collection.breakOut)

can we avoid the 2nd iteration?

Page 43: Effective Scala (JavaDay Riga 2013)

Common pitfalldef pick(users: Seq[User])

Good question!

mutable or immutable?

import scala.collection.immutabledef pick(users: immutable.Seq[User])remedy

Page 44: Effective Scala (JavaDay Riga 2013)

Implicits

Page 45: Effective Scala (JavaDay Riga 2013)

Limit the scope of implicits

Page 46: Effective Scala (JavaDay Riga 2013)

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

Page 47: Effective Scala (JavaDay Riga 2013)

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)

Page 48: Effective Scala (JavaDay Riga 2013)

avoid implicit views

Page 49: Effective Scala (JavaDay Riga 2013)

Typeclass patterntrait 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

Page 50: Effective Scala (JavaDay Riga 2013)

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]

Page 51: Effective Scala (JavaDay Riga 2013)

Typeclass - typesafecase 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

Page 52: Effective Scala (JavaDay Riga 2013)

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

Page 53: Effective Scala (JavaDay Riga 2013)

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

Page 54: Effective Scala (JavaDay Riga 2013)

Looking ahead

Page 55: Effective Scala (JavaDay Riga 2013)

Scala In DepthJoshua Suereth

Level up!

http://www.manning.com/suereth/

Page 56: Effective Scala (JavaDay Riga 2013)

Effective Scala

Thanks to @jsuereth for a good portion of the slides’ content, and @heathermiller for the presentation style

@mircodotta