59
Coding in Style J. Suereth Senior Software Engineer 粋なコード

Coding in Style

Embed Size (px)

DESCRIPTION

Scala Conference in Japan 2013

Citation preview

Page 1: Coding in Style

Coding in StyleJ. Suereth

Senior Software Engineer

粋なコード

Page 2: Coding in Style

Agenda● The Scala mindset● Scala 2.10 new features● A brave new venture

Scala 風に考える/Scala 2.10 の新機能/その先へ

Page 3: Coding in Style

Favor Expressions

文より式

Page 4: Coding in Style

def isAwesome(data: Data): Boolean = { if(data.awesome) return true if(data.lame) return false return data.contains("Tasty Sandwich")}

Page 5: Coding in Style

def isAwesome(data: Data): Boolean = if(data.awesome) true else if(data.lame) false else (data contains "Tasty Sandwich")}

Page 6: Coding in Style

def isAwesome(data: Data): Boolean = (data.awesome || (!data.lame) || (data contains "Tasty Sandwich"))

Page 7: Coding in Style

Embrace Operator Notation

演算子(中置)記法を取り入れよう

Page 8: Coding in Style

def privs(user: Option[User]): Privileges = user.map(findUserPrivileges).getOrElse( NoPrivs)

Page 9: Coding in Style

def privs(user: Option[User]): Privileges = (user map findUserPrivileges getOrElse NoPrivs)

Page 10: Coding in Style

Let the language do the work

SUDO Make me a variable

作業を言語に任せる

Page 11: Coding in Style

def slurp(file: File): String = { var input: InputStream = null var output: OutputStream = null var read = 0 try { input = new FileInputStream(file) output = new StringOutputStream() val buf = new Array[Byte](BUF_SIZE) read = input.read(buf)

while(read > 0) { output.write(buf, 0, read)

read = input.read(buf)

}

} finally { if(input != null) input.close() if(output != null) output.close() }

if(output != null) return output.toString return null}

Page 12: Coding in Style

def slurp(in: File): String = { val in = new FileInputStream(in) val out = new StringWriter() val buf = new Array[Byte](BUF_SIZE) def read(): Unit = (in read buf) match { case 0 => () case n => out.write(buf, 0, n) read() } try read() finally in.close() out.toString}

Page 13: Coding in Style

Tail-recursioN! @tailrec def read(): Unit = (in read buf) match { case 0 => () case n => out.write(buf, 0, n) read() }

Page 14: Coding in Style

Tail-recursioN! @tailrec def read(): Unit = (in read buf) match { case 0 => () case n => out.write(buf, 0, n) read() }

Base Case

Page 15: Coding in Style

Tail-recursioN! @tailrec def read(): Unit = (in read buf) match { case 0 => () case n => out.write(buf, 0, n) read() }

Recursive Case

Page 16: Coding in Style

If it seems useful, look for it

便利そうであれば、まずは探そう

Page 17: Coding in Style

def countEm(counts: Seq[Int]): Int = { var total = 0 for(count <- counts) total += count total}

Page 18: Coding in Style

def countEm(counts: Seq[Int]): Int = counts.sum

Page 19: Coding in Style

Collections!● Scala collections have > 100 useful methods● By far the biggest reason to use Scala is

manipulating data using collections

Scala を使う最大の理由: コレクションを使ったデータ処理

Page 20: Coding in Style

Aim Higherhigher-order-functions, that is

上を狙おう (高階関数)

Page 21: Coding in Style

def sort[T]( data: Seq[T])( lessThan: (T,T) => Boolean): Seq[T] = ...

Page 22: Coding in Style

Why higher order functions?def sort[T]( data: Seq[T])( lessThan: (T,T) => Boolean): Seq[T] = ... Abstract the algorithm (how to

do something) from the goal (what to do)

目的(何がしたいか) とアルゴリズム(どうやるか) を分離する

Page 23: Coding in Style

New w/ Scala 2.10Features that alter your daily code

Scala 2.10 の新機能

Page 24: Coding in Style

Build strings the nice wayinterpolators

文字列生成を楽に

Page 25: Coding in Style

val HAI = "HI"val name = "SQUARE"val height = 100val width = 20

scala> val x = s"${HAI}"x: String = HI

scala> f"$name is $height%04d meters by $width%04d meters"res0: String = SQUARE is 0100 meters by 0020 meters

Page 26: Coding in Style

Keep the abstract........ well abstract.

抽象的なものは抽象的に

Page 27: Coding in Style

A Graph Library APItrait Node[N] { def value: N}trait Edge[N,E] { def value: E def from: Node[N] def to: Node[N]}

trait Graph[N,E] { type Nd = Node[N] type Ed = Edge[N,E] def nodes: Set[Nd] def edges(n: Nd): Seq[Ed]}

Page 28: Coding in Style

A Graph Library APItrait Node[N] { def value: N}trait Edge[N,E] { def value: E def from: Node[N] def to: Node[N]}

trait Graph[N,E] { type Nd = Node[N] type Ed = Edge[N,E] def nodes: Set[Nd] def edges(n: Nd): Seq[Ed]}

Great for implementers, but where's all the friendly user methods?

実装する人にはいいけど、trait を使う人にやさしくない

Page 29: Coding in Style

Add behaviorwith shiny new value classes and implicit classes

値クラスとimplicit クラスで振る舞いを追加する

Page 30: Coding in Style

object Graph { implicit class Ops[N,E](val g: Graph[N,E]) extends AnyVal {

def isAcyclic: Boolean = cycles forall (c => (c drop 1).isEmpty)

def cycles: Set[Set[Node[N]]] = ... compute using tarjan or other algorithm ... } }

Page 31: Coding in Style

object Graph { implicit class Ops[N,E](val g: Graph[N,E]) extends AnyVal {

def isAcyclic: Boolean = cycles forall (c => (c drop 1).isEmpty)

def cycles: Set[Set[Node[N]]] = ... compute using tarjan or other algorithm ... } }

Page 32: Coding in Style

Fast at runtime, tooval graph: Graph[N, E] = ...if(graph.isCyclic) sys.error("O NOES")

val graph: Graph[N, E] = ...if(Graph.Ops.isCyclic(graph)) sys.error("O NOES")

Translates to static helper method call

実行時には static メソッドの呼び出しへと変換される

Page 33: Coding in Style

Cheat in an EmergencyWith Dynamic Types

いざという時の動的型

Page 34: Coding in Style

class MapHelper(json: Map[String,AnyRef]) extends Dynamic {

def selectDynamic(name: String) = (json get name getOrElse sys.error(s"Attribute $name not found in json: $json"))

}

Page 35: Coding in Style

scala> val m = new MapHelper(Map[String,AnyRef]("name" -> "Jimmy", "age" -> "10"))m: MapHelper = MapHelper@683f67e0

scala> m.nameres1: AnyRef = Jimmy

scala> m.sexjava.lang.RuntimeException: Attribute sex not found in json: Map(name -> Jimmy, age -> 10)

Page 36: Coding in Style

Promise the Future!Make sure to deliver

Promise とFuture (約束は守りましょう)

Page 37: Coding in Style

import scala.concurrent._import scala.concurrent.ExecutionContext.Implicits.globalscala> val x = promise[Int]scala> val y = x.futurescala> y.isCompletedres5: Boolean = falsescala> x success 5scala> y.isCompletedres7: Boolean = truescala> y.valueres9: Option[Either[Throwable,Int]] = Some(Right(5))

Page 38: Coding in Style

Why not Java Futures?

executor.submit(new Callable<Integer>() { def call(): Integer = { Thread sleep 3000L new Integer(5) }})

future { Thread sleep 30000L 5}

Creating!

Page 39: Coding in Style

Why not Java Futures?

val x: Future[Integer] = ...

x.get(10, TimeUnit.SECONDS)

val x: Future[Int] = ...

Await.result(x, 10 seconds)

Blocking!

Page 40: Coding in Style

Why not Java Futures?

N/Aval x: Future[Int] = ...val y: Future[Int] = x map { result => result + 5 }

Non-Blocking

chains!

Page 41: Coding in Style

Scala's FuturesProvide a lightweight model for asynchronous, non-blocking execution that can be chained and joined throughout your application.

Future: 軽量な非同期・ノンブロッキング実行モデル

Page 42: Coding in Style

Staying Async!See http://jsuereth.com/intro-to-fp/

いつも非同期で

Page 43: Coding in Style

trait AsynchService { def users: Future[Seq[User]] def projects(user: User):Future[Seq[Project]]}

Page 44: Coding in Style

def allprojects(api: AsynchService): Future[Set[Project]] = (Future.traverse(api.users)(api.projects) map (_.flatten.toSet))

Page 45: Coding in Style

Traverse is fork joindef traverse[A]( seq: Future[Seq[A]] )( op: A => Future[B] ): Future[Seq[B]] = ....

traverse は fork/join を用いて行われる

Page 46: Coding in Style
Page 47: Coding in Style

Feeling Crazy?Manipulate some ASTs

ちょっと遊ぶ?AST をいじろう

Page 48: Coding in Style

object MacroAsserts {

def assert(cond: Boolean, expr: String) = macro assertImpl

def assertImpl(c: Context)( cond: c.Expr[Boolean], msg: c.Expr[String] ): c.Expr[Unit] = if(sys.env("SCALA_ASSERT") == "true") c.reify(if(cond.splice) sys.error(msg.splice)) else c.reify(())}

Page 49: Coding in Style

object MacroAsserts {

def assert(cond: Boolean, expr: String) = macro assertImpl

def assertImpl(c: Context)( cond: c.Expr[Boolean], msg: c.Expr[String] ): c.Expr[Unit] = if(sys.env("SCALA_ASSERT") == "true") c.reify(if(cond.splice) sys.error(msg.splice)) else c.reify(())}

What the user sees

Page 50: Coding in Style

object MacroAsserts {

def assert(cond: Boolean, expr: String) = macro assertImpl

def assertImpl(c: Context)( cond: c.Expr[Boolean], msg: c.Expr[String] ): c.Expr[Unit] = if(sys.env("SCALA_ASSERT") == "true") c.reify(if(cond.splice) sys.error(msg.splice)) else c.reify(())}

What the compiler uses

Page 51: Coding in Style

Tree Transformationobject Bar { assert(false, "THIS IS A BAD OBJECT")}

構文木の変換

Page 52: Coding in Style

object Bar {

} Expr[Boolean]Expr[Any]

Page 53: Coding in Style

object Bar {

} Expr[Boolean]Expr[Any]

Macro

Page 54: Coding in Style

object Bar {

}Expr[Unit] Macro

Page 55: Coding in Style

object Bar { ()

}

Page 56: Coding in Style

A Brave New WorldWelcome to

すばらしい新世界へようこそ

Page 57: Coding in Style

What's coming in Scala 2.11?Nothing certain, but a list of possibilities● Smaller

○ Modularization of components?○ Eviction of deprecated libraries?

● Faster○ More reliable inlining?○ Method-Handle based closures?

● Stabler○ Fix ALL THE BUGS○ Reflection API Stabilizes?

より小さく、高速で、安定した Scala 2.11

Page 58: Coding in Style

ResourcesCollections: http://docs.scala-lang.org/overviews/collections/introduction.htmlString Interpolation: http://docs.scala-lang.org/overviews/core/string-interpolation.htmlValue Classes: http://docs.scala-lang.org/overviews/core/value-classes.htmlFutures: http://docs.scala-lang.org/overviews/core/futures.htmlReflection: http://docs.scala-lang.org/overviews/reflection/overview.htmlMacros: http://docs.scala-lang.org/overviews/macros/overview.html

Page 59: Coding in Style

Questions?

質問ある?