SlideShare a Scribd company logo
Functional	OO	ImperativeFunctional	OO	Imperative
ScalaScala
関数型オブジェクト指向命関数型オブジェクト指向命
令型	Scala令型	Scala
Sébastien	Doeraene	--	セバスチャン·ドゥラン
June	28,	2019	--	Scala	Matsuri	--	2019年6⽉28⽇
@sjrdoeraene
Scala	Center,	
École	polytechnique	fédérale	de	Lausanne
 
	           	
scala.epfl.ch
1
BasicsBasics
Japanese	line	1
Japanese	line	2
2
def times2(xs: List[Int]): List[Int] = {
var result: List[Int] = Nil
var i = 0
while (i < xs.length) {
result = result :+ (xs(i) * 2)
i += 1
}
result
}
3
def times2(xs: List[Int]): List[Int] = {
var result: List[Int] = Nil
for (i <- 0 until xs.length) {
result = result :+ (xs(i) * 2)
}
result
}
4
def times2(xs: List[Int]): List[Int] = {
val builder = List.newBuilder[Int]
for (i <- 0 until xs.length) {
builder += xs(i) * 2
}
builder.result()
}
5
def times2(xs: List[Int]): List[Int] = {
val builder = List.newBuilder[Int]
for (x <- xs) {
builder += x * 2
}
builder.result()
}
6
def times2(xs: List[Int]): List[Int] = {
for (x <- xs)
yield x * 2
}
def times2(xs: List[Int]): List[Int] = {
xs.map(x => x * 2)
}
7
Sometimes,	builders	are	better
Japanese	line	1
Japanese	line	2
8
def fromPathClasspath(classpath: Seq[Path]): (Seq[IRContainer], Seq[Path]) = {
val containers = Seq.newBuilder[IRContainer]
val paths = Seq.newBuilder[Path]
for (entry <- classpath if Files.exists(entry)) {
val attrs = Files.readAttributes(entry, classOf[BasicFileAttributes])
if (attrs.isDirectory()) {
walkIR(entry) { (path, attrs) =>
containers += IRContainer.fromIRFile(...)
paths += path
}
} else if (entry.getFileName().toString().endsWith(".jar")) {
containers += new JarIRContainer(entry, attrs.lastModifiedTime())
paths += entry
} else {
throw new IllegalArgumentException("Illegal classpath entry " + entry)
}
}
(containers.result(), paths.result())
}
9
def fromPathClasspath(classpath: Seq[Path]): (Seq[IRContainer], Seq[Path]) = {
val containers = Seq.newBuilder[IRContainer]
val paths = Seq.newBuilder[Path]
for (entry <- classpath if Files.exists(entry)) {
val attrs = Files.readAttributes(entry, classOf[BasicFileAttributes])
if (attrs.isDirectory()) {
walkIR(entry) { (path, attrs) =>
containers += IRContainer.fromIRFile(...)
paths += path
}
} else if (entry.getFileName().toString().endsWith(".jar")) {
containers += new JarIRContainer(entry, attrs.lastModifiedTime())
paths += entry
} else {
throw new IllegalArgumentException("Illegal classpath entry " + entry)
}
}
(containers.result(), paths.result())
}
9
Sometimes,	 s	are	better
Japanese	line	1
Japanese	line	2
10
var test = {
genIsScalaJSObject(obj) &&
genIsClassNameInAncestors(...)
}
def typeOfTest(typeString: String): js.Tree = ...
if (isAncestorOfString)
test = test || typeOfTest("string")
if (isAncestorOfHijackedNumberClass) {
test = test || typeOfTest("number")
if (useBigIntForLongs)
test = test || genCallHelper("isLong", obj)
}
if (isAncestorOfBoxedBooleanClass)
test = test || typeOfTest("boolean")
if (isAncestorOfBoxedCharacterClass)
test = test || (obj instanceof envField("Char"))
test
11
var test = {
genIsScalaJSObject(obj) &&
genIsClassNameInAncestors(...)
}
def typeOfTest(typeString: String): js.Tree = ...
if (isAncestorOfString)
test = test || typeOfTest("string")
if (isAncestorOfHijackedNumberClass) {
test = test || typeOfTest("number")
if (useBigIntForLongs)
test = test || genCallHelper("isLong", obj)
}
if (isAncestorOfBoxedBooleanClass)
test = test || typeOfTest("boolean")
if (isAncestorOfBoxedCharacterClass)
test = test || (obj instanceof envField("Char"))
test
11
val test0 = {
genIsScalaJSObject(obj) &&
genIsClassNameInAncestors(...)
}
def typeOfTest(typeString: String): js.Tree = ...
val test1 =
if (isAncestorOfString) test0 || typeOfTest("string")
else test0
val test3 = if (isAncestorOfHijackedNumberClass) {
val test2 = test1 || typeOfTest("number")
if (useBigIntForLongs) test2 || genCallHelper("isLong", obj)
else test2
}
val test4 =
if (isAncestorOfBoxedBooleanClass) test3 || typeOfTest("boolean")
else test3
val test5 =
if (isAncestorOfBoxedCharacterClass) test4 || (obj instanceof envField("Char"))
else test4
test5
12
val test0 = {
genIsScalaJSObject(obj) &&
genIsClassNameInAncestors(...)
}
def typeOfTest(typeString: String): js.Tree = ...
val test1 =
if (isAncestorOfString) test0 || typeOfTest("string")
else test0
val test3 = if (isAncestorOfHijackedNumberClass) {
val test2 = test1 || typeOfTest("number")
if (useBigIntForLongs) test2 || genCallHelper("isLong", obj)
else test2
}
val test4 =
if (isAncestorOfBoxedBooleanClass) test3 || typeOfTest("boolean")
else test3
val test5 =
if (isAncestorOfBoxedCharacterClass) test4 || (obj instanceof envField("Char"))
else test4
test5
12
val test0 = {
genIsScalaJSObject(obj) &&
genIsClassNameInAncestors(...)
}
def typeOfTest(typeString: String): js.Tree = ...
val test1 =
if (isAncestorOfString) test0 || typeOfTest("string")
else test0
val test3 = if (isAncestorOfHijackedNumberClass) {
val test2 = test1 || typeOfTest("number")
if (useBigIntForLongs) test2 || genCallHelper("isLong", obj)
else test2
}
val test4 =
if (isAncestorOfBoxedBooleanClass) test3 || typeOfTest("boolean")
else test3
val test5 =
if (isAncestorOfBoxedCharacterClass) test4 || (obj instanceof envField("Char"))
else test4
test5
12
val test0 = {
genIsScalaJSObject(obj) &&
genIsClassNameInAncestors(...)
}
def typeOfTest(typeString: String): js.Tree = ...
val test1 =
if (isAncestorOfString) test0 || typeOfTest("string")
else test0
val test3 = if (isAncestorOfHijackedNumberClass) {
val test2 = test1 || typeOfTest("number")
if (useBigIntForLongs) test2 || genCallHelper("isLong", obj)
else test2
}
val test4 =
if (isAncestorOfBoxedBooleanClass) test3 || typeOfTest("boolean")
else test3
val test5 =
if (isAncestorOfBoxedCharacterClass) test4 || (obj instanceof envField("Char"))
else test4
test5
12
In	the	(super)	smallIn	the	(super)	small
Immutable/functional	API
Locally	imperative	implementation	(if	more	readable)
Japanese	line	1
Japanese	line	2
13
Algorithms	with	mutable	internal	dataAlgorithms	with	mutable	internal	data
structuresstructures
The	 	of	Scala.js
The	change	detection	algorithm	of	the	optimizer
Japanese	line	1
Japanese	line	2
14
At	the	instance	levelAt	the	instance	level
Japanese	line	1
Japanese	line	2
15
final class Emitter(config: CommonPhaseConfig) {
def emitAll(unit: LinkingUnit, builder: JSLineBuilder,
logger: Logger): Unit = {
...
}
}
16
final class Emitter(config: CommonPhaseConfig) {
private class State(val lastMentionedDangerousGlobalRefs: Set[String]) {
val jsGen: JSGen = new JSGen(..., lastMentionedDangerousGlobalRefs)
val classEmitter: ClassEmitter = new ClassEmitter(jsGen)
val coreJSLib: WithGlobals[js.Tree] = CoreJSLib.build(jsGen)
}
private var state: State = new State(Set.empty)
private def jsGen: JSGen = state.jsGen
private def classEmitter: ClassEmitter = state.classEmitter
private def coreJSLib: WithGlobals[js.Tree] = state.coreJSLib
private val classCaches = mutable.Map.empty[List[String], ClassCache]
def emitAll(unit: LinkingUnit, builder: JSLineBuilder,
logger: Logger): Unit = {
...
classCaches.getOrElseUpdate(..., ...)
...
val mentionedDangerousGlobalRefs = ...
state = new State(mentionedDangerousGlobalRefs)
...
}
}
17
final class Emitter(config: CommonPhaseConfig) {
private class State(val lastMentionedDangerousGlobalRefs: Set[String]) {
val jsGen: JSGen = new JSGen(..., lastMentionedDangerousGlobalRefs)
val classEmitter: ClassEmitter = new ClassEmitter(jsGen)
val coreJSLib: WithGlobals[js.Tree] = CoreJSLib.build(jsGen)
}
private var state: State = new State(Set.empty)
private def jsGen: JSGen = state.jsGen
private def classEmitter: ClassEmitter = state.classEmitter
private def coreJSLib: WithGlobals[js.Tree] = state.coreJSLib
private val classCaches = mutable.Map.empty[List[String], ClassCache]
def emitAll(unit: LinkingUnit, builder: JSLineBuilder,
logger: Logger): Unit = {
...
classCaches.getOrElseUpdate(..., ...)
...
val mentionedDangerousGlobalRefs = ...
state = new State(mentionedDangerousGlobalRefs)
...
}
}
17
final class Emitter(config: CommonPhaseConfig) {
private class State(val lastMentionedDangerousGlobalRefs: Set[String]) {
val jsGen: JSGen = new JSGen(..., lastMentionedDangerousGlobalRefs)
val classEmitter: ClassEmitter = new ClassEmitter(jsGen)
val coreJSLib: WithGlobals[js.Tree] = CoreJSLib.build(jsGen)
}
private var state: State = new State(Set.empty)
private def jsGen: JSGen = state.jsGen
private def classEmitter: ClassEmitter = state.classEmitter
private def coreJSLib: WithGlobals[js.Tree] = state.coreJSLib
private val classCaches = mutable.Map.empty[List[String], ClassCache]
def emitAll(unit: LinkingUnit, builder: JSLineBuilder,
logger: Logger): Unit = {
...
classCaches.getOrElseUpdate(..., ...)
...
val mentionedDangerousGlobalRefs = ...
state = new State(mentionedDangerousGlobalRefs)
...
}
}
17
final class Emitter(config: CommonPhaseConfig) {
private class State(val lastMentionedDangerousGlobalRefs: Set[String]) {
val jsGen: JSGen = new JSGen(..., lastMentionedDangerousGlobalRefs)
val classEmitter: ClassEmitter = new ClassEmitter(jsGen)
val coreJSLib: WithGlobals[js.Tree] = CoreJSLib.build(jsGen)
}
private var state: State = new State(Set.empty)
private def jsGen: JSGen = state.jsGen
private def classEmitter: ClassEmitter = state.classEmitter
private def coreJSLib: WithGlobals[js.Tree] = state.coreJSLib
private val classCaches = mutable.Map.empty[List[String], ClassCache]
def emitAll(unit: LinkingUnit, builder: JSLineBuilder,
logger: Logger): Unit = {
...
classCaches.getOrElseUpdate(..., ...)
...
val mentionedDangerousGlobalRefs = ...
state = new State(mentionedDangerousGlobalRefs)
...
}
}
17
At	the	instance	levelAt	the	instance	level
Immutable/functional	object	API
Mutable	state	carried	between	invocations
But	not	observable	from	the	outside
The	state	is	encapsulated	using	object-orientation
Japanese	line	1
Japanese	line	2
18
At	the	instance	levelAt	the	instance	level
Not	possible	using	pure	functional	programming
Difficult	to	reason	about	if	the	state	is	observable	(using
an	imperative	API)
Unique	power	of	combining	functional	programming,
object-orientation	and	imperative	features
Japanese	line	1
Japanese	line	2
19
Used	at	several	levels:
The	emitter
The	optimizer
The	caches	for	 	files
The	all-encompassing	 	method
etc.
Japanese	line	1
Japanese	line	2
20
Open	class	hierarchiesOpen	class	hierarchies
Japanese	line	1
Japanese	line	2
21
So	far:	 	traits	and	 	classes
Japanese	line	1
Japanese	line	2
22
/** A backend of a standard Scala.js linker. */
abstract class LinkerBackend {
/** Core specification that this linker backend implements. */
val coreSpec: CoreSpec
/** Symbols this backend needs to be present in the linking unit. */
val symbolRequirements: SymbolRequirement
/** Emit the given LinkingUnit to the target output. */
def emit(unit: LinkingUnit, output: LinkerOutput, logger: Logger)(
implicit ec: ExecutionContext): Future[Unit]
}
23
/** The basic backend for the Scala.js linker. */
final class BasicLinkerBackend(config: LinkerBackendImpl.Config)
extends LinkerBackend {
val coreSpec = config.commonConfig.coreSpec
private[this] val emitter = new Emitter(config.commonConfig)
val symbolRequirements: SymbolRequirement = emitter.symbolRequirements
def emit(unit: LinkingUnit, output: LinkerOutput, logger: Logger)(
implicit ec: ExecutionContext): Future[Unit] = {
...
val builder = new JSFileBuilder
emitter.emitAll(unit, builder, logger)
OutputFileImpl.fromOutputFile(output.jsFile)
.writeFull(builer.complete())
...
}
}
24
/** The Closure backend of the Scala.js linker. */
final class ClosureLinkerBackend(config: LinkerBackendImpl.Config)
extends LinkerBackend {
val coreSpec = config.commonConfig.coreSpec
private[this] val emitter = new Emitter(config.commonConfig)
val symbolRequirements: SymbolRequirement = emitter.symbolRequirements
def emit(unit: LinkingUnit, output: LinkerOutput, logger: Logger)(
implicit ec: ExecutionContext): Future[Unit] = {
...
val builer = new ClosureModuleBuilder
emitter.emitAll(unit, builer, logger)
val closureModules = makeClosureModules(builder.result())
val result = closureCompiler.compileModules(..., closureModules, ...)
writeResult(result, ...)
...
}
}
25
Possible	to	write	your	own	Scala.js	backend	in	user-space
	actually	does	that,
to	collect	imported	modules	for	Webpack
Japanese	line	1
Japanese	line	2
26
/** A JavaScript execution environment.
*
* This can run and interact with JavaScript code.
*
* Any implementation is expected to be fully thread-safe.
*/
trait JSEnv {
/** Human-readable name for this [[JSEnv]] */
val name: String
/** Starts a new (asynchronous) JS run. */
def start(input: Input, config: RunConfig): JSRun
/** Like [[start]], but initializes a communication channel. */
def startWithCom(input: Input, config: RunConfig,
onMessage: String => Unit): JSComRun
}
27
In	the	main	repo,	one	implementation:	
Completely	unrelated	but	compatible	implementations
are	in	other	repos:
Custom	environments	in	users'	builds
Japanese	line	1
Japanese	line	2
28
Custom	for	comprehensionsCustom	for	comprehensions
the	M	word
Japanese	line	1
Japanese	line	2
29
def genMethod(className: String, method: MethodDef)(
implicit globalKnowledge: GlobalKnowledge): WithGlobals[js.Tree] = {
val methodBody = method.body.getOrElse(
throw new AssertionError("Cannot generate an abstract method"))
implicit val pos = method.pos
val namespace = method.flags.namespace
val methodFunWithGlobals: WithGlobals[js.Function] =
desugarToFunction(className, method.args, methodBody, method.resultType)
methodFunWithGlobals.flatMap { methodFun =>
if (namespace != MemberNamespace.Public) {
...
} else {
if (useClasses) {
for (propName <- genPropertyName(method.name)) yield {
js.MethodDef(static = false, propName, methodFun.args,
methodFun.body)
}
} else {
genAddToPrototype(className, method.name, methodFun)
}
}
}
}
30
def genMethod(className: String, method: MethodDef)(
implicit globalKnowledge: GlobalKnowledge): WithGlobals[js.Tree] = {
val methodBody = method.body.getOrElse(
throw new AssertionError("Cannot generate an abstract method"))
implicit val pos = method.pos
val namespace = method.flags.namespace
val methodFunWithGlobals: WithGlobals[js.Function] =
desugarToFunction(className, method.args, methodBody, method.resultType)
methodFunWithGlobals.flatMap { methodFun =>
if (namespace != MemberNamespace.Public) {
...
} else {
if (useClasses) {
for (propName <- genPropertyName(method.name)) yield {
js.MethodDef(static = false, propName, methodFun.args,
methodFun.body)
}
} else {
genAddToPrototype(className, method.name, methodFun)
}
}
}
}
30
def genMethod(className: String, method: MethodDef)(
implicit globalKnowledge: GlobalKnowledge): WithGlobals[js.Tree] = {
val methodBody = method.body.getOrElse(
throw new AssertionError("Cannot generate an abstract method"))
implicit val pos = method.pos
val namespace = method.flags.namespace
val methodFunWithGlobals: WithGlobals[js.Function] =
desugarToFunction(className, method.args, methodBody, method.resultType)
methodFunWithGlobals.flatMap { methodFun =>
if (namespace != MemberNamespace.Public) {
...
} else {
if (useClasses) {
for (propName <- genPropertyName(method.name)) yield {
js.MethodDef(static = false, propName, methodFun.args,
methodFun.body)
}
} else {
genAddToPrototype(className, method.name, methodFun)
}
}
}
}
30
def genMethod(className: String, method: MethodDef)(
implicit globalKnowledge: GlobalKnowledge): WithGlobals[js.Tree] = {
val methodBody = method.body.getOrElse(
throw new AssertionError("Cannot generate an abstract method"))
implicit val pos = method.pos
val namespace = method.flags.namespace
val methodFunWithGlobals: WithGlobals[js.Function] =
desugarToFunction(className, method.args, methodBody, method.resultType)
methodFunWithGlobals.flatMap { methodFun =>
if (namespace != MemberNamespace.Public) {
...
} else {
if (useClasses) {
for (propName <- genPropertyName(method.name)) yield {
js.MethodDef(static = false, propName, methodFun.args,
methodFun.body)
}
} else {
genAddToPrototype(className, method.name, methodFun)
}
}
}
}
30
/** A monad that associates a set of global variable names to a value. */
private[emitter] final case class WithGlobals[+A](
value: A, globalVarNames: Set[String]) {
def map[B](f: A => B): WithGlobals[B] =
WithGlobals(f(value), globalVarNames)
def flatMap[B](f: A => WithGlobals[B]): WithGlobals[B] = {
val t = f(value)
WithGlobals(t.value, globalVarNames ++ t.globalVarNames)
}
}
private[emitter] object WithGlobals {
/** Constructs a `WithGlobals` with an empty set `globalVarNames`. */
def apply[A](value: A): WithGlobals[A] =
new WithGlobals(value, Set.empty)
def list[A](xs: List[WithGlobals[A]]): WithGlobals[List[A]] =
...
def option[A](xs: Option[WithGlobals[A]]): WithGlobals[Option[A]] =
...
} 31
Further	exploration	of	the	codeFurther	exploration	of	the	code
Time	permitting
Japanese	line	1
Japanese	line	2
32
         	
         scala-js.org scala.epfl.ch
33

More Related Content

ODP
Scala traits training by Sanjeev Kumar @Kick Start Scala traits & Play, organ...
PDF
Hello Swift Final 5/5 - Structures and Classes
PDF
From Java to Scala - advantages and possible risks
PDF
Scala 2013 review
PDF
Scala for Java Developers - Intro
PDF
The Ring programming language version 1.5.2 book - Part 32 of 181
PPT
Scala - brief intro
ODP
1.2 scala basics
Scala traits training by Sanjeev Kumar @Kick Start Scala traits & Play, organ...
Hello Swift Final 5/5 - Structures and Classes
From Java to Scala - advantages and possible risks
Scala 2013 review
Scala for Java Developers - Intro
The Ring programming language version 1.5.2 book - Part 32 of 181
Scala - brief intro
1.2 scala basics

What's hot (20)

PDF
Scala cheatsheet
PDF
Workshop Scala
PDF
PDF
Scala taxonomy
PPTX
11. session 11 functions and objects
PDF
The Ring programming language version 1.9 book - Part 41 of 210
PDF
Scala-对Java的修正和超越
PPTX
All about scala
PDF
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream
PDF
Starting with Scala : Frontier Developer's Meetup December 2010
PDF
Scala jargon cheatsheet
PDF
The Ring programming language version 1.2 book - Part 22 of 84
PDF
Scala for Java Developers (Silicon Valley Code Camp 13)
PDF
Scala vs Java 8 in a Java 8 World
ODP
Functional Objects & Function and Closures
PDF
Model-Driven Software Development - Static Analysis & Error Checking
PDF
JavaScript objects and functions
PPTX
Scala for curious
PDF
Scala vs java 8
PDF
Scala: Object-Oriented Meets Functional, by Iulian Dragos
Scala cheatsheet
Workshop Scala
Scala taxonomy
11. session 11 functions and objects
The Ring programming language version 1.9 book - Part 41 of 210
Scala-对Java的修正和超越
All about scala
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream
Starting with Scala : Frontier Developer's Meetup December 2010
Scala jargon cheatsheet
The Ring programming language version 1.2 book - Part 22 of 84
Scala for Java Developers (Silicon Valley Code Camp 13)
Scala vs Java 8 in a Java 8 World
Functional Objects & Function and Closures
Model-Driven Software Development - Static Analysis & Error Checking
JavaScript objects and functions
Scala for curious
Scala vs java 8
Scala: Object-Oriented Meets Functional, by Iulian Dragos
Ad

Similar to Functional Object-Oriented Imperative Scala / 関数型オブジェクト指向命令型 Scala by Sébastien Doeraene (20)

PDF
(How) can we benefit from adopting scala?
PDF
Scala coated JVM
PDF
Meet scala
PPT
An introduction to scala
PDF
Introduction to scala
ODP
Introducing scala
PDF
Scala Bootcamp 1
PDF
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
PDF
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
PDF
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
PDF
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
ODP
PDF
Introduction to Scala
PDF
A Prelude of Purity: Scaling Back ZIO
PDF
Coding in Style
ODP
Introduction to Scala
PPT
Scala introduction
PDF
ハイブリッド言語Scalaを使う
PDF
Beyond xUnit example-based testing: property-based testing with ScalaCheck
PPTX
(How) can we benefit from adopting scala?
Scala coated JVM
Meet scala
An introduction to scala
Introduction to scala
Introducing scala
Scala Bootcamp 1
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
Introduction to Scala
A Prelude of Purity: Scaling Back ZIO
Coding in Style
Introduction to Scala
Scala introduction
ハイブリッド言語Scalaを使う
Beyond xUnit example-based testing: property-based testing with ScalaCheck
Ad

More from scalaconfjp (20)

PDF
脆弱性対策のためのClean Architecture ~脆弱性に対するレジリエンスを確保せよ~
PDF
Alp x BizReach SaaS事業を営む2社がお互い気になることをゆるゆる聞いてみる会
PDF
GraalVM Overview Compact version
PDF
Run Scala Faster with GraalVM on any Platform / GraalVMで、どこでもScalaを高速実行しよう by...
PPTX
Monitoring Reactive Architecture Like Never Before / 今までになかったリアクティブアーキテクチャの監視...
PPTX
Scala 3, what does it means for me? / Scala 3って、私にはどんな影響があるの? by Joan Goyeau
PDF
Scala ♥ Graal by Flavio Brasil
PPTX
Introduction to GraphQL in Scala
PDF
Safety Beyond Types
PDF
Reactive Kafka with Akka Streams
PDF
Reactive microservices with play and akka
PDF
Scalaに対して意識の低いエンジニアがScalaで何したかの話, by 芸者東京エンターテインメント
PDF
DWANGO by ドワンゴ
PDF
OCTOPARTS by M3, Inc.
PDF
Try using Aeromock by Marverick, Inc.
PDF
統計をとって高速化する
Scala開発 by CyberZ,Inc.
PDF
Short Introduction of Implicit Conversion by TIS, Inc.
PPTX
ビズリーチ x ScalaMatsuri by BIZREACH, Inc.
PDF
sbt, past and future / sbt, 傾向と対策
PDF
The Evolution of Scala / Scala進化論
脆弱性対策のためのClean Architecture ~脆弱性に対するレジリエンスを確保せよ~
Alp x BizReach SaaS事業を営む2社がお互い気になることをゆるゆる聞いてみる会
GraalVM Overview Compact version
Run Scala Faster with GraalVM on any Platform / GraalVMで、どこでもScalaを高速実行しよう by...
Monitoring Reactive Architecture Like Never Before / 今までになかったリアクティブアーキテクチャの監視...
Scala 3, what does it means for me? / Scala 3って、私にはどんな影響があるの? by Joan Goyeau
Scala ♥ Graal by Flavio Brasil
Introduction to GraphQL in Scala
Safety Beyond Types
Reactive Kafka with Akka Streams
Reactive microservices with play and akka
Scalaに対して意識の低いエンジニアがScalaで何したかの話, by 芸者東京エンターテインメント
DWANGO by ドワンゴ
OCTOPARTS by M3, Inc.
Try using Aeromock by Marverick, Inc.
統計をとって高速化する
Scala開発 by CyberZ,Inc.
Short Introduction of Implicit Conversion by TIS, Inc.
ビズリーチ x ScalaMatsuri by BIZREACH, Inc.
sbt, past and future / sbt, 傾向と対策
The Evolution of Scala / Scala進化論

Recently uploaded (20)

PPTX
Log360_SIEM_Solutions Overview PPT_Feb 2020.pptx
PPTX
Introduction to Artificial Intelligence
PDF
Odoo Companies in India – Driving Business Transformation.pdf
PDF
top salesforce developer skills in 2025.pdf
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
PDF
Designing Intelligence for the Shop Floor.pdf
PDF
Understanding Forklifts - TECH EHS Solution
PDF
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
PDF
Navsoft: AI-Powered Business Solutions & Custom Software Development
PPTX
Computer Software and OS of computer science of grade 11.pptx
PPTX
Operating system designcfffgfgggggggvggggggggg
PDF
Digital Systems & Binary Numbers (comprehensive )
PDF
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
PDF
Cost to Outsource Software Development in 2025
PPTX
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
PDF
PTS Company Brochure 2025 (1).pdf.......
PDF
How to Choose the Right IT Partner for Your Business in Malaysia
PDF
Product Update: Alluxio AI 3.7 Now with Sub-Millisecond Latency
PPTX
Why Generative AI is the Future of Content, Code & Creativity?
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
Log360_SIEM_Solutions Overview PPT_Feb 2020.pptx
Introduction to Artificial Intelligence
Odoo Companies in India – Driving Business Transformation.pdf
top salesforce developer skills in 2025.pdf
Wondershare Filmora 15 Crack With Activation Key [2025
Designing Intelligence for the Shop Floor.pdf
Understanding Forklifts - TECH EHS Solution
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
Navsoft: AI-Powered Business Solutions & Custom Software Development
Computer Software and OS of computer science of grade 11.pptx
Operating system designcfffgfgggggggvggggggggg
Digital Systems & Binary Numbers (comprehensive )
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
Cost to Outsource Software Development in 2025
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
PTS Company Brochure 2025 (1).pdf.......
How to Choose the Right IT Partner for Your Business in Malaysia
Product Update: Alluxio AI 3.7 Now with Sub-Millisecond Latency
Why Generative AI is the Future of Content, Code & Creativity?
Which alternative to Crystal Reports is best for small or large businesses.pdf

Functional Object-Oriented Imperative Scala / 関数型オブジェクト指向命令型 Scala by Sébastien Doeraene

  • 4. def times2(xs: List[Int]): List[Int] = { var result: List[Int] = Nil var i = 0 while (i < xs.length) { result = result :+ (xs(i) * 2) i += 1 } result } 3
  • 5. def times2(xs: List[Int]): List[Int] = { var result: List[Int] = Nil for (i <- 0 until xs.length) { result = result :+ (xs(i) * 2) } result } 4
  • 6. def times2(xs: List[Int]): List[Int] = { val builder = List.newBuilder[Int] for (i <- 0 until xs.length) { builder += xs(i) * 2 } builder.result() } 5
  • 7. def times2(xs: List[Int]): List[Int] = { val builder = List.newBuilder[Int] for (x <- xs) { builder += x * 2 } builder.result() } 6
  • 8. def times2(xs: List[Int]): List[Int] = { for (x <- xs) yield x * 2 } def times2(xs: List[Int]): List[Int] = { xs.map(x => x * 2) } 7
  • 10. def fromPathClasspath(classpath: Seq[Path]): (Seq[IRContainer], Seq[Path]) = { val containers = Seq.newBuilder[IRContainer] val paths = Seq.newBuilder[Path] for (entry <- classpath if Files.exists(entry)) { val attrs = Files.readAttributes(entry, classOf[BasicFileAttributes]) if (attrs.isDirectory()) { walkIR(entry) { (path, attrs) => containers += IRContainer.fromIRFile(...) paths += path } } else if (entry.getFileName().toString().endsWith(".jar")) { containers += new JarIRContainer(entry, attrs.lastModifiedTime()) paths += entry } else { throw new IllegalArgumentException("Illegal classpath entry " + entry) } } (containers.result(), paths.result()) } 9
  • 11. def fromPathClasspath(classpath: Seq[Path]): (Seq[IRContainer], Seq[Path]) = { val containers = Seq.newBuilder[IRContainer] val paths = Seq.newBuilder[Path] for (entry <- classpath if Files.exists(entry)) { val attrs = Files.readAttributes(entry, classOf[BasicFileAttributes]) if (attrs.isDirectory()) { walkIR(entry) { (path, attrs) => containers += IRContainer.fromIRFile(...) paths += path } } else if (entry.getFileName().toString().endsWith(".jar")) { containers += new JarIRContainer(entry, attrs.lastModifiedTime()) paths += entry } else { throw new IllegalArgumentException("Illegal classpath entry " + entry) } } (containers.result(), paths.result()) } 9
  • 13. var test = { genIsScalaJSObject(obj) && genIsClassNameInAncestors(...) } def typeOfTest(typeString: String): js.Tree = ... if (isAncestorOfString) test = test || typeOfTest("string") if (isAncestorOfHijackedNumberClass) { test = test || typeOfTest("number") if (useBigIntForLongs) test = test || genCallHelper("isLong", obj) } if (isAncestorOfBoxedBooleanClass) test = test || typeOfTest("boolean") if (isAncestorOfBoxedCharacterClass) test = test || (obj instanceof envField("Char")) test 11
  • 14. var test = { genIsScalaJSObject(obj) && genIsClassNameInAncestors(...) } def typeOfTest(typeString: String): js.Tree = ... if (isAncestorOfString) test = test || typeOfTest("string") if (isAncestorOfHijackedNumberClass) { test = test || typeOfTest("number") if (useBigIntForLongs) test = test || genCallHelper("isLong", obj) } if (isAncestorOfBoxedBooleanClass) test = test || typeOfTest("boolean") if (isAncestorOfBoxedCharacterClass) test = test || (obj instanceof envField("Char")) test 11
  • 15. val test0 = { genIsScalaJSObject(obj) && genIsClassNameInAncestors(...) } def typeOfTest(typeString: String): js.Tree = ... val test1 = if (isAncestorOfString) test0 || typeOfTest("string") else test0 val test3 = if (isAncestorOfHijackedNumberClass) { val test2 = test1 || typeOfTest("number") if (useBigIntForLongs) test2 || genCallHelper("isLong", obj) else test2 } val test4 = if (isAncestorOfBoxedBooleanClass) test3 || typeOfTest("boolean") else test3 val test5 = if (isAncestorOfBoxedCharacterClass) test4 || (obj instanceof envField("Char")) else test4 test5 12
  • 16. val test0 = { genIsScalaJSObject(obj) && genIsClassNameInAncestors(...) } def typeOfTest(typeString: String): js.Tree = ... val test1 = if (isAncestorOfString) test0 || typeOfTest("string") else test0 val test3 = if (isAncestorOfHijackedNumberClass) { val test2 = test1 || typeOfTest("number") if (useBigIntForLongs) test2 || genCallHelper("isLong", obj) else test2 } val test4 = if (isAncestorOfBoxedBooleanClass) test3 || typeOfTest("boolean") else test3 val test5 = if (isAncestorOfBoxedCharacterClass) test4 || (obj instanceof envField("Char")) else test4 test5 12
  • 17. val test0 = { genIsScalaJSObject(obj) && genIsClassNameInAncestors(...) } def typeOfTest(typeString: String): js.Tree = ... val test1 = if (isAncestorOfString) test0 || typeOfTest("string") else test0 val test3 = if (isAncestorOfHijackedNumberClass) { val test2 = test1 || typeOfTest("number") if (useBigIntForLongs) test2 || genCallHelper("isLong", obj) else test2 } val test4 = if (isAncestorOfBoxedBooleanClass) test3 || typeOfTest("boolean") else test3 val test5 = if (isAncestorOfBoxedCharacterClass) test4 || (obj instanceof envField("Char")) else test4 test5 12
  • 18. val test0 = { genIsScalaJSObject(obj) && genIsClassNameInAncestors(...) } def typeOfTest(typeString: String): js.Tree = ... val test1 = if (isAncestorOfString) test0 || typeOfTest("string") else test0 val test3 = if (isAncestorOfHijackedNumberClass) { val test2 = test1 || typeOfTest("number") if (useBigIntForLongs) test2 || genCallHelper("isLong", obj) else test2 } val test4 = if (isAncestorOfBoxedBooleanClass) test3 || typeOfTest("boolean") else test3 val test5 = if (isAncestorOfBoxedCharacterClass) test4 || (obj instanceof envField("Char")) else test4 test5 12
  • 22. final class Emitter(config: CommonPhaseConfig) { def emitAll(unit: LinkingUnit, builder: JSLineBuilder, logger: Logger): Unit = { ... } } 16
  • 23. final class Emitter(config: CommonPhaseConfig) { private class State(val lastMentionedDangerousGlobalRefs: Set[String]) { val jsGen: JSGen = new JSGen(..., lastMentionedDangerousGlobalRefs) val classEmitter: ClassEmitter = new ClassEmitter(jsGen) val coreJSLib: WithGlobals[js.Tree] = CoreJSLib.build(jsGen) } private var state: State = new State(Set.empty) private def jsGen: JSGen = state.jsGen private def classEmitter: ClassEmitter = state.classEmitter private def coreJSLib: WithGlobals[js.Tree] = state.coreJSLib private val classCaches = mutable.Map.empty[List[String], ClassCache] def emitAll(unit: LinkingUnit, builder: JSLineBuilder, logger: Logger): Unit = { ... classCaches.getOrElseUpdate(..., ...) ... val mentionedDangerousGlobalRefs = ... state = new State(mentionedDangerousGlobalRefs) ... } } 17
  • 24. final class Emitter(config: CommonPhaseConfig) { private class State(val lastMentionedDangerousGlobalRefs: Set[String]) { val jsGen: JSGen = new JSGen(..., lastMentionedDangerousGlobalRefs) val classEmitter: ClassEmitter = new ClassEmitter(jsGen) val coreJSLib: WithGlobals[js.Tree] = CoreJSLib.build(jsGen) } private var state: State = new State(Set.empty) private def jsGen: JSGen = state.jsGen private def classEmitter: ClassEmitter = state.classEmitter private def coreJSLib: WithGlobals[js.Tree] = state.coreJSLib private val classCaches = mutable.Map.empty[List[String], ClassCache] def emitAll(unit: LinkingUnit, builder: JSLineBuilder, logger: Logger): Unit = { ... classCaches.getOrElseUpdate(..., ...) ... val mentionedDangerousGlobalRefs = ... state = new State(mentionedDangerousGlobalRefs) ... } } 17
  • 25. final class Emitter(config: CommonPhaseConfig) { private class State(val lastMentionedDangerousGlobalRefs: Set[String]) { val jsGen: JSGen = new JSGen(..., lastMentionedDangerousGlobalRefs) val classEmitter: ClassEmitter = new ClassEmitter(jsGen) val coreJSLib: WithGlobals[js.Tree] = CoreJSLib.build(jsGen) } private var state: State = new State(Set.empty) private def jsGen: JSGen = state.jsGen private def classEmitter: ClassEmitter = state.classEmitter private def coreJSLib: WithGlobals[js.Tree] = state.coreJSLib private val classCaches = mutable.Map.empty[List[String], ClassCache] def emitAll(unit: LinkingUnit, builder: JSLineBuilder, logger: Logger): Unit = { ... classCaches.getOrElseUpdate(..., ...) ... val mentionedDangerousGlobalRefs = ... state = new State(mentionedDangerousGlobalRefs) ... } } 17
  • 26. final class Emitter(config: CommonPhaseConfig) { private class State(val lastMentionedDangerousGlobalRefs: Set[String]) { val jsGen: JSGen = new JSGen(..., lastMentionedDangerousGlobalRefs) val classEmitter: ClassEmitter = new ClassEmitter(jsGen) val coreJSLib: WithGlobals[js.Tree] = CoreJSLib.build(jsGen) } private var state: State = new State(Set.empty) private def jsGen: JSGen = state.jsGen private def classEmitter: ClassEmitter = state.classEmitter private def coreJSLib: WithGlobals[js.Tree] = state.coreJSLib private val classCaches = mutable.Map.empty[List[String], ClassCache] def emitAll(unit: LinkingUnit, builder: JSLineBuilder, logger: Logger): Unit = { ... classCaches.getOrElseUpdate(..., ...) ... val mentionedDangerousGlobalRefs = ... state = new State(mentionedDangerousGlobalRefs) ... } } 17
  • 32. /** A backend of a standard Scala.js linker. */ abstract class LinkerBackend { /** Core specification that this linker backend implements. */ val coreSpec: CoreSpec /** Symbols this backend needs to be present in the linking unit. */ val symbolRequirements: SymbolRequirement /** Emit the given LinkingUnit to the target output. */ def emit(unit: LinkingUnit, output: LinkerOutput, logger: Logger)( implicit ec: ExecutionContext): Future[Unit] } 23
  • 33. /** The basic backend for the Scala.js linker. */ final class BasicLinkerBackend(config: LinkerBackendImpl.Config) extends LinkerBackend { val coreSpec = config.commonConfig.coreSpec private[this] val emitter = new Emitter(config.commonConfig) val symbolRequirements: SymbolRequirement = emitter.symbolRequirements def emit(unit: LinkingUnit, output: LinkerOutput, logger: Logger)( implicit ec: ExecutionContext): Future[Unit] = { ... val builder = new JSFileBuilder emitter.emitAll(unit, builder, logger) OutputFileImpl.fromOutputFile(output.jsFile) .writeFull(builer.complete()) ... } } 24
  • 34. /** The Closure backend of the Scala.js linker. */ final class ClosureLinkerBackend(config: LinkerBackendImpl.Config) extends LinkerBackend { val coreSpec = config.commonConfig.coreSpec private[this] val emitter = new Emitter(config.commonConfig) val symbolRequirements: SymbolRequirement = emitter.symbolRequirements def emit(unit: LinkingUnit, output: LinkerOutput, logger: Logger)( implicit ec: ExecutionContext): Future[Unit] = { ... val builer = new ClosureModuleBuilder emitter.emitAll(unit, builer, logger) val closureModules = makeClosureModules(builder.result()) val result = closureCompiler.compileModules(..., closureModules, ...) writeResult(result, ...) ... } } 25
  • 36. /** A JavaScript execution environment. * * This can run and interact with JavaScript code. * * Any implementation is expected to be fully thread-safe. */ trait JSEnv { /** Human-readable name for this [[JSEnv]] */ val name: String /** Starts a new (asynchronous) JS run. */ def start(input: Input, config: RunConfig): JSRun /** Like [[start]], but initializes a communication channel. */ def startWithCom(input: Input, config: RunConfig, onMessage: String => Unit): JSComRun } 27
  • 39. def genMethod(className: String, method: MethodDef)( implicit globalKnowledge: GlobalKnowledge): WithGlobals[js.Tree] = { val methodBody = method.body.getOrElse( throw new AssertionError("Cannot generate an abstract method")) implicit val pos = method.pos val namespace = method.flags.namespace val methodFunWithGlobals: WithGlobals[js.Function] = desugarToFunction(className, method.args, methodBody, method.resultType) methodFunWithGlobals.flatMap { methodFun => if (namespace != MemberNamespace.Public) { ... } else { if (useClasses) { for (propName <- genPropertyName(method.name)) yield { js.MethodDef(static = false, propName, methodFun.args, methodFun.body) } } else { genAddToPrototype(className, method.name, methodFun) } } } } 30
  • 40. def genMethod(className: String, method: MethodDef)( implicit globalKnowledge: GlobalKnowledge): WithGlobals[js.Tree] = { val methodBody = method.body.getOrElse( throw new AssertionError("Cannot generate an abstract method")) implicit val pos = method.pos val namespace = method.flags.namespace val methodFunWithGlobals: WithGlobals[js.Function] = desugarToFunction(className, method.args, methodBody, method.resultType) methodFunWithGlobals.flatMap { methodFun => if (namespace != MemberNamespace.Public) { ... } else { if (useClasses) { for (propName <- genPropertyName(method.name)) yield { js.MethodDef(static = false, propName, methodFun.args, methodFun.body) } } else { genAddToPrototype(className, method.name, methodFun) } } } } 30
  • 41. def genMethod(className: String, method: MethodDef)( implicit globalKnowledge: GlobalKnowledge): WithGlobals[js.Tree] = { val methodBody = method.body.getOrElse( throw new AssertionError("Cannot generate an abstract method")) implicit val pos = method.pos val namespace = method.flags.namespace val methodFunWithGlobals: WithGlobals[js.Function] = desugarToFunction(className, method.args, methodBody, method.resultType) methodFunWithGlobals.flatMap { methodFun => if (namespace != MemberNamespace.Public) { ... } else { if (useClasses) { for (propName <- genPropertyName(method.name)) yield { js.MethodDef(static = false, propName, methodFun.args, methodFun.body) } } else { genAddToPrototype(className, method.name, methodFun) } } } } 30
  • 42. def genMethod(className: String, method: MethodDef)( implicit globalKnowledge: GlobalKnowledge): WithGlobals[js.Tree] = { val methodBody = method.body.getOrElse( throw new AssertionError("Cannot generate an abstract method")) implicit val pos = method.pos val namespace = method.flags.namespace val methodFunWithGlobals: WithGlobals[js.Function] = desugarToFunction(className, method.args, methodBody, method.resultType) methodFunWithGlobals.flatMap { methodFun => if (namespace != MemberNamespace.Public) { ... } else { if (useClasses) { for (propName <- genPropertyName(method.name)) yield { js.MethodDef(static = false, propName, methodFun.args, methodFun.body) } } else { genAddToPrototype(className, method.name, methodFun) } } } } 30
  • 43. /** A monad that associates a set of global variable names to a value. */ private[emitter] final case class WithGlobals[+A]( value: A, globalVarNames: Set[String]) { def map[B](f: A => B): WithGlobals[B] = WithGlobals(f(value), globalVarNames) def flatMap[B](f: A => WithGlobals[B]): WithGlobals[B] = { val t = f(value) WithGlobals(t.value, globalVarNames ++ t.globalVarNames) } } private[emitter] object WithGlobals { /** Constructs a `WithGlobals` with an empty set `globalVarNames`. */ def apply[A](value: A): WithGlobals[A] = new WithGlobals(value, Set.empty) def list[A](xs: List[WithGlobals[A]]): WithGlobals[List[A]] = ... def option[A](xs: Option[WithGlobals[A]]): WithGlobals[Option[A]] = ... } 31