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

Coding in Style

May 10, 2015

Download

Documents

scalaconfjp

Scala Conference in Japan 2013
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
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?

質問ある?