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

What's hot (20)

PDF
Scala cheatsheet
Arduino Aficionado
 
PDF
Workshop Scala
Bert Van Vreckem
 
PDF
Scala
Sven Efftinge
 
PDF
Scala taxonomy
Radim Pavlicek
 
PPTX
11. session 11 functions and objects
Phúc Đỗ
 
PDF
The Ring programming language version 1.9 book - Part 41 of 210
Mahmoud Samir Fayed
 
PDF
Scala-对Java的修正和超越
Caoyuan Deng
 
PPTX
All about scala
Yardena Meymann
 
PDF
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream
Ruslan Shevchenko
 
PDF
Starting with Scala : Frontier Developer's Meetup December 2010
Derek Chen-Becker
 
PDF
Scala jargon cheatsheet
Ruslan Shevchenko
 
PDF
The Ring programming language version 1.2 book - Part 22 of 84
Mahmoud Samir Fayed
 
PDF
Scala for Java Developers (Silicon Valley Code Camp 13)
Ramnivas Laddad
 
PDF
Scala vs Java 8 in a Java 8 World
BTI360
 
ODP
Functional Objects & Function and Closures
Sandip Kumar
 
PDF
Model-Driven Software Development - Static Analysis & Error Checking
Eelco Visser
 
PDF
JavaScript objects and functions
Victor Verhaagen
 
PPTX
Scala for curious
Tim (dev-tim) Zadorozhniy
 
PDF
Scala vs java 8
François Sarradin
 
PDF
Scala: Object-Oriented Meets Functional, by Iulian Dragos
3Pillar Global
 
Scala cheatsheet
Arduino Aficionado
 
Workshop Scala
Bert Van Vreckem
 
Scala taxonomy
Radim Pavlicek
 
11. session 11 functions and objects
Phúc Đỗ
 
The Ring programming language version 1.9 book - Part 41 of 210
Mahmoud Samir Fayed
 
Scala-对Java的修正和超越
Caoyuan Deng
 
All about scala
Yardena Meymann
 
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream
Ruslan Shevchenko
 
Starting with Scala : Frontier Developer's Meetup December 2010
Derek Chen-Becker
 
Scala jargon cheatsheet
Ruslan Shevchenko
 
The Ring programming language version 1.2 book - Part 22 of 84
Mahmoud Samir Fayed
 
Scala for Java Developers (Silicon Valley Code Camp 13)
Ramnivas Laddad
 
Scala vs Java 8 in a Java 8 World
BTI360
 
Functional Objects & Function and Closures
Sandip Kumar
 
Model-Driven Software Development - Static Analysis & Error Checking
Eelco Visser
 
JavaScript objects and functions
Victor Verhaagen
 
Scala for curious
Tim (dev-tim) Zadorozhniy
 
Scala vs java 8
François Sarradin
 
Scala: Object-Oriented Meets Functional, by Iulian Dragos
3Pillar Global
 

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

PDF
Coding in Style
scalaconfjp
 
PDF
Scala Paradigms
Tom Flaherty
 
PDF
ハイブリッド言語Scalaを使う
bpstudy
 
PPT
SDC - Einführung in Scala
Christian Baranowski
 
KEY
Scala基礎勉強会: Featherweight Scalaの紹介および型付け規則の決定可能性について
Hiroki Mizuno
 
PDF
Contravariant functors in scala
Piotr Paradziński
 
KEY
SacalaZa #1
Hiroki Mizuno
 
PPT
An introduction to scala
Mohsen Zainalpour
 
PDF
Scala intro workshop
Fredrik Vraalsen
 
PPT
Scala presentation by Aleksandar Prokopec
Loïc Descotte
 
PDF
The Essence of the Iterator Pattern (pdf)
Eric Torreborre
 
PDF
Generic Functional Programming with Type Classes
Tapio Rautonen
 
PPTX
API design: using type classes and dependent types
bmlever
 
PDF
High Wizardry in the Land of Scala
djspiewak
 
PPTX
Scala in a Java 8 World
Daniel Blyth
 
PDF
Scala for Java Developers
Martin Ockajak
 
PPTX
The Essence of the Iterator Pattern
Eric Torreborre
 
PPT
JBUG 11 - Scala For Java Programmers
Tikal Knowledge
 
PDF
여자개발자모임터 6주년 개발 세미나 - Scala Language
Ashal aka JOKER
 
PDF
Beyond Scala Lens
Julien Truffaut
 
Coding in Style
scalaconfjp
 
Scala Paradigms
Tom Flaherty
 
ハイブリッド言語Scalaを使う
bpstudy
 
SDC - Einführung in Scala
Christian Baranowski
 
Scala基礎勉強会: Featherweight Scalaの紹介および型付け規則の決定可能性について
Hiroki Mizuno
 
Contravariant functors in scala
Piotr Paradziński
 
SacalaZa #1
Hiroki Mizuno
 
An introduction to scala
Mohsen Zainalpour
 
Scala intro workshop
Fredrik Vraalsen
 
Scala presentation by Aleksandar Prokopec
Loïc Descotte
 
The Essence of the Iterator Pattern (pdf)
Eric Torreborre
 
Generic Functional Programming with Type Classes
Tapio Rautonen
 
API design: using type classes and dependent types
bmlever
 
High Wizardry in the Land of Scala
djspiewak
 
Scala in a Java 8 World
Daniel Blyth
 
Scala for Java Developers
Martin Ockajak
 
The Essence of the Iterator Pattern
Eric Torreborre
 
JBUG 11 - Scala For Java Programmers
Tikal Knowledge
 
여자개발자모임터 6주년 개발 세미나 - Scala Language
Ashal aka JOKER
 
Beyond Scala Lens
Julien Truffaut
 
Ad

More from scalaconfjp (20)

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

Recently uploaded (20)

PDF
Linux Certificate of Completion - LabEx Certificate
VICTOR MAESTRE RAMIREZ
 
PDF
Powering GIS with FME and VertiGIS - Peak of Data & AI 2025
Safe Software
 
PPTX
An Introduction to ZAP by Checkmarx - Official Version
Simon Bennetts
 
PDF
Build It, Buy It, or Already Got It? Make Smarter Martech Decisions
bbedford2
 
PDF
Salesforce CRM Services.VALiNTRY360
VALiNTRY360
 
PDF
Mobile CMMS Solutions Empowering the Frontline Workforce
CryotosCMMSSoftware
 
PPT
MergeSortfbsjbjsfk sdfik k
RafishaikIT02044
 
PPTX
Feb 2021 Cohesity first pitch presentation.pptx
enginsayin1
 
PDF
Understanding the Need for Systemic Change in Open Source Through Intersectio...
Imma Valls Bernaus
 
PDF
Alexander Marshalov - How to use AI Assistants with your Monitoring system Q2...
VictoriaMetrics
 
PPTX
Tally_Basic_Operations_Presentation.pptx
AditiBansal54083
 
PPTX
Equipment Management Software BIS Safety UK.pptx
BIS Safety Software
 
PPTX
Writing Better Code - Helping Developers make Decisions.pptx
Lorraine Steyn
 
PPTX
3uTools Full Crack Free Version Download [Latest] 2025
muhammadgurbazkhan
 
PPTX
Why Businesses Are Switching to Open Source Alternatives to Crystal Reports.pptx
Varsha Nayak
 
PPTX
The Role of a PHP Development Company in Modern Web Development
SEO Company for School in Delhi NCR
 
PDF
GetOnCRM Speeds Up Agentforce 3 Deployment for Enterprise AI Wins.pdf
GetOnCRM Solutions
 
PPTX
Engineering the Java Web Application (MVC)
abhishekoza1981
 
PPTX
Platform for Enterprise Solution - Java EE5
abhishekoza1981
 
PPTX
Revolutionizing Code Modernization with AI
KrzysztofKkol1
 
Linux Certificate of Completion - LabEx Certificate
VICTOR MAESTRE RAMIREZ
 
Powering GIS with FME and VertiGIS - Peak of Data & AI 2025
Safe Software
 
An Introduction to ZAP by Checkmarx - Official Version
Simon Bennetts
 
Build It, Buy It, or Already Got It? Make Smarter Martech Decisions
bbedford2
 
Salesforce CRM Services.VALiNTRY360
VALiNTRY360
 
Mobile CMMS Solutions Empowering the Frontline Workforce
CryotosCMMSSoftware
 
MergeSortfbsjbjsfk sdfik k
RafishaikIT02044
 
Feb 2021 Cohesity first pitch presentation.pptx
enginsayin1
 
Understanding the Need for Systemic Change in Open Source Through Intersectio...
Imma Valls Bernaus
 
Alexander Marshalov - How to use AI Assistants with your Monitoring system Q2...
VictoriaMetrics
 
Tally_Basic_Operations_Presentation.pptx
AditiBansal54083
 
Equipment Management Software BIS Safety UK.pptx
BIS Safety Software
 
Writing Better Code - Helping Developers make Decisions.pptx
Lorraine Steyn
 
3uTools Full Crack Free Version Download [Latest] 2025
muhammadgurbazkhan
 
Why Businesses Are Switching to Open Source Alternatives to Crystal Reports.pptx
Varsha Nayak
 
The Role of a PHP Development Company in Modern Web Development
SEO Company for School in Delhi NCR
 
GetOnCRM Speeds Up Agentforce 3 Deployment for Enterprise AI Wins.pdf
GetOnCRM Solutions
 
Engineering the Java Web Application (MVC)
abhishekoza1981
 
Platform for Enterprise Solution - Java EE5
abhishekoza1981
 
Revolutionizing Code Modernization with AI
KrzysztofKkol1
 

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