Sbt is a build tool that uses a state-command design where commands make changes to the build state. It operates incrementally by evaluating tasks only when needed. Key concepts include applicative composition which sequences tasks in dependency order, and "happens before" which defines task evaluation order. Future updates may include build linting, caching, and server support for improved IDE integration.
12. which state is it changing?
commands changes
help, tasks no changes
projects, project hello build structure
set name := "foo" build structure
<command1>; <command2> both
++ 2.13.0, ++ 2.13.0!, +<command> both
act command disk
21. distributed events
• a → b (a happens before b)
• a ↛ b (a does not happen before b)
• 2 distinct events a and b are said to
be concurrent if a ↛ b and b ↛ a
22. distributed events
• a → b (a happens before b)
• a ↛ b (a does not happen before b)
• 2 distinct events a and b are said to
be concurrent if a ↛ b and b ↛ a
2 events are concurrent if neither can causality affect
each other
23. Applicative functor
scala> (3.some, 2.some) mapN { _ + _ }
res8: Option[Int] = Some(5)
scala> (none[Int], 5.some) mapN { _ - _ }
res9: Option[Int] = None
See 'Oh, All the things you'll traverse' by Luka Jacobowitz
24. for comprehension
getLine flatMap { x =>
print(length(x)) flatMap { _ =>
getLine flatMap { y =>
IO(x ++ y)
}
}
}
for {
x <- getLine
_ <- print(length(x))
y <- getLine
} yield x ++ y
def procedural: Unit = {
val x = getLine
print(length(x))
val y = getLine
x ++ y
}
25. build.sbt DSL
// sbt 0.12 style
foo <<= (compile in Compile, bar) map { (c, b) =>
doSomething(b)
}
// sbt 1.x style
foo := {
val c = (Compile / compile).value
val b = bar.value
doSomething(b)
}
26. build.sbt DSL
// sbt 0.12 style
foo <<= (compile in Compile, bar) map { (c, b) =>
doSomething(b)
}
// sbt 1.x style
foo := {
val c = (Compile / compile).value
val b = bar.value
doSomething(b)
}
Applicative composition
27. build.sbt DSL
foo := {
val c = (Compile / compile).value
val b = bar.value
doSomething(b)
}
Compile / compile bar
foo
"happens before"
28. build.sbt DSL
foo := {
val c = (Compile / compile).value
val b = bar.value
doSomething(b)
}
Compile / compile bar
foo
"happens before"
line of sand in time-space
29. Applicative composition
foo := {
val c = (Compile / compile).value
val b = bar.value
doSomething(b)
}
Test / test := {
val c = (Compile / compile).value
val f = foo.value
}
Compile / compile bar
foo
"happens before"
Test / test
"happens before"
31. why Applicative composition?
Compile / compile bar
foo
"happens before"
Test / test
"happens before"
1. minimality (executes task at most once, for input
that changed)
evaluated only once
32. why Applicative composition?
Compile / compile bar
foo
"happens before"
Test / test
"happens before"
1. minimality
2. automatic parallel processing
33. act command
• given a task, creates a plan that evaluates the task
in current and aggregated subprojects
• concurrent tasks are evaluated in parallel
lazy val root = (project in file("."))
.aggregate(util, core)
.settings(...)
lazy val util = (project in
file("util"))
.dependsOn(core)
lazy val core = (project in
file("core"))
34. act command
• how does it relate with State?
s0 s1 s2
reload (settings) act (task) act (task)
35. tasks vs commands
• prefer tasks for plugin extension
• tasks compose automatically
• command composition is stateful / sequential
50. 2020.03 mixtape
COVID-19 real-time update in US (https://
coronavirus.1point3acres.com/en)
Coronavirus update and guidance (https://
www.flattenthecurve.com/)
about me