SlideShare une entreprise Scribd logo
1  sur  116
Télécharger pour lire hors ligne
atomically {
delete your actors
}
John A. De Goes — @jdegoes
Wiem Zine Elabidine — @wiemzin
The Bank Heist The Hero Become a Hero!
The Bank Heist
The Bank
#1
#1
12
def transfer(from: Account, to: Account,
amount: Amount): Unit = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
13
def transfer(from: Account, to: Account,
amount: Amount): Unit = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
14
def transfer(from: Account, to: Account,
amount: Amount): Unit = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
15
def transfer(from: Account, to: Account,
amount: Amount): Unit = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
Double-Spend Exploits
$1 M
$1 M
$1 M $2 M
def transfer(from: Account, to: Account,
amount: Amount) = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
def transfer(from: Account, to: Account,
amount: Amount) = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
Thread 1 Thread 2
Race Condition Exploit
def transfer(from: Account, to: Account,
amount: Amount) = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
def transfer(from: Account, to: Account,
amount: Amount) = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
Thread 1 Thread 2
Race Condition Exploit
20
class Account {
var balance : Amount
var accountID : AccountID
var name : String
val opened : Instant
val status : AccountStatus
val tpe : AccountType
}
balance 200,000
accountID 2816157231
... ...
Main Memory
balance 200,000
accountID 2816157231
... ...
Core 1 Cache
balance 200,000
accountID 2816157231
... ...
Core 2 Cache
def transfer(from: Account, to: Account,
amount: Amount) = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
def transfer(from: Account, to: Account,
amount: Amount) = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
Thread 1 Thread 2
Stale Cache Exploit
from.balance -= amount
4: getfield #2
7: invokevirtual #3
10: aload_2
11: invokevirtual #3
14: isub
15: invokestatic #4
18: dup_x1
19: putfield #2
def transfer(from: Account, to: Account,
amount: Amount) = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
def transfer(from: Account, to: Account,
amount: Amount) = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
Thread 1 Thread 2
Nonatomic Instruction Exploit
abstract class Account {
trait State {
@volatile var balance: BigDecimal = _
}
val state: State
def modify[A](f: State => A): A = this.synchronized {
val result = f(state)
this.notifyAll()
result
}
def await(): Unit = this.synchronized { this.wait() }
}
def transfer(from: Account, to: Account,
amount: Amount): Unit = {
var loop = true
while (loop) {
from.modify { state =>
if (state.balance >= amount.value) {
state.balance -= amount.value
to.modify(state => state.balance += amount.value)
loop = false
}
else from.await()
}
}
transfer(from, to, amount) transfer(to, from, amount)
Thread 1 Thread 2
Deadlock Exploit
class Account extends Actor {
var balance = Amount.zero
var todos = List.empty[(ActorRef, Message)]
def receive = {
case Deposit(amount) =>
balance = balance + amount.value
sender ! Success(balance)
todos.foreach { case (s, m) => self ! m }
todos = Nil
case v @ Withdraw(amount) =>
if (balance >= amount.value) {
balance = balance - amount.value
sender ! Success(balance)
} else todos = (sender, v) :: todos
case Balance => sender ! Success(balance)
}
}
def transfer(from: ActorRef, to: ActorRef,
amount: Amount)(implicit garbage: Timeout): Unit =
(from ? Withdraw(amount)).flatMap { _ =>
to ? Deposit(amount)
}
for {
john <- johnAccount ? Balance
wiem <- wiemAccount ? Balance
} yield
if (wiem.value > john.value)
transfer(wiem, cafe, amount)
else transfer(john, cafe, amount)
$70
$99
for {
john <- johnAccount ? Balance
wiem <- wiemAccount ? Balance
} yield
if (wiem.value > john.value)
transfer(wiem, cafe, amount)
else transfer(john, cafe, amount)
$70
$6,000,000 $99
for {
john <- johnAccount ? Balance
wiem <- wiemAccount ? Balance
} yield
if (wiem.value > john.value)
transfer(wiem, cafe, amount)
else transfer(john, cafe, amount)
$70
$6,000,000 $99
$70
~$6m
for {
john <- johnAccount ? Balance
wiem <- wiemAccount ? Balance
} yield
if (wiem.value > john.value)
transfer(wiem, cafe, amount)
else transfer(john, cafe, amount)
$10 $99
$70
-$60
for {
john <- johnAccount ? Balance
wiem <- wiemAccount ? Balance
} yield
if (wiem.value > john.value)
transfer(wiem, cafe, amount)
else transfer(john, cafe, amount)
$99
46
def transfer(from : TRef[Account],
to : TRef[Account],
amount : Amount): UIO[Unit] =
atomically {
for {
balance <- from.get
_ <- check(balance >= amount)
_ <- from.update(_ - amount)
_ <- to.update(_ + amount)
} yield ()
}
47
def transfer(from : TRef[Account],
to : TRef[Account],
amount : Amount): UIO[Unit] =
atomically {
for {
balance <- from.get
_ <- check(balance >= amount)
_ <- from.update(_ - amount)
_ <- to.update(_ + amount)
} yield ()
}
48
def transfer(from : TRef[Account],
to : TRef[Account],
amount : Amount): UIO[Unit] =
atomically {
for {
balance <- from.get
_ <- check(balance >= amount)
_ <- from.update(_ - amount)
_ <- to.update(_ + amount)
} yield ()
}
49
def transfer(from : TRef[Account],
to : TRef[Account],
amount : Amount): UIO[Unit] =
atomically {
for {
balance <- from.get
_ <- check(balance >= amount)
_ <- from.update(_ - amount)
_ <- to.update(_ + amount)
} yield ()
}
50
def transfer(from : TRef[Account],
to : TRef[Account],
amount : Amount): UIO[Unit] =
atomically {
for {
balance <- from.get
_ <- check(balance >= amount)
_ <- from.update(_ - amount)
_ <- to.update(_ + amount)
} yield ()
}
51
def transfer(from : TRef[Account],
to : TRef[Account],
amount : Amount): UIO[Unit] =
atomically {
for {
balance <- from.get
_ <- check(balance >= amount)
_ <- from.update(_ - amount)
_ <- to.update(_ + amount)
} yield ()
}
The Hero
STM: Software Transactional Memory
Provides the ability to atomically commit a series of
reads and writes to transactional memory when a set
of conditions is satisfied.
STM
STM
...Op 2Op 1 Op n
Final
State
Initial
State
commit
failure - rollback
retry - rollback
complete complete
STM
STM[E, A]
A transaction,
which models
reads & writes,
and can fail, retry,
or succeed.
TRef[A]
A transactional
reference, which
is read & written
inside STM
transactions.
STM[E, A]
Succeed with a
value of type A
Fail with an
error of type E
STM
STM
STM[E, A]
A transaction,
which models
reads & writes,
and can fail, retry,
or succeed.
TRef[A]
A transactional
reference, which
is read & written
inside STM
transactions.
TRef[A]
An immutable value
of type A
STM
STM
STM
STM
STM
Composable
trait TRef[A] {
val get: STM[Nothing, A]
def set(newValue: A): STM[Nothing, Unit]
def update(f: A => A): STM[Nothing, A]
def modify[B](f: A => (B, A)): STM[Nothing, B]
}
object TRef {
def make[A](a: A): STM[Nothing, TRef[A]]
}
TRef
trait TRef[A] {
val get: STM[Nothing, A]
def set(newValue: A): STM[Nothing, Unit]
def update(f: A => A): STM[Nothing, A]
def modify[B](f: A => (B, A)): STM[Nothing, B]
}
object TRef {
def make[A](a: A): STM[Nothing, TRef[A]]
}
TRef
trait TRef[A] {
val get: STM[Nothing, A]
def set(newValue: A): STM[Nothing, Unit]
def update(f: A => A): STM[Nothing, A]
def modify[B](f: A => (B, A)): STM[Nothing, B]
}
object TRef {
def make[A](a: A): STM[Nothing, TRef[A]]
}
TRef
trait TRef[A] {
val get: STM[Nothing, A]
def set(newValue: A): STM[Nothing, Unit]
def update(f: A => A): STM[Nothing, A]
def modify[B](f: A => (B, A)): STM[Nothing, B]
}
object TRef {
def make[A](a: A): STM[Nothing, TRef[A]]
}
TRef
trait TRef[A] {
val get: STM[Nothing, A]
def set(newValue: A): STM[Nothing, Unit]
def update(f: A => A): STM[Nothing, A]
def modify[B](f: A => (B, A)): STM[Nothing, B]
}
object TRef {
def make[A](a: A): STM[Nothing, TRef[A]]
}
TRef
trait STM[+E, +A] {
def commit: IO[E, A] = STM.atomically { this }
}
object STM {
def atomically[E, A](stm: STM[E, A]): IO[E, A]
}
STM - Commit
val hello: STM[Nothing, String] =
STM.succeed("Welcome to Scalar")
STM - Succeed
val sumBalances: STM[Nothing, Int] =
balance1.get.flatMap(a =>
balance2.get.map(b => a + b))
STM - map & flatMap
val sumBalances: STM[Nothing, Int] =
for {
a <- balance1.get
b <- balance2.get
} yield a + b
STM - map & flatMap
STM - Fail
def debit(sender: TRef[Amount], amount: Amount):
STM[String, Amount] =
for {
balance <- sender.update(_ - amount)
_ <- if (balance < 0) STM.fail("Insufficient funds")
else STM.succeed(())
} yield balance
def debitSuccess(sender: TRef[Amount],
amount: Amount): STM[Nothing, Boolean] =
debit(sender, amount).fold(_ => false, _ => true)
STM - Fold
def debitWithBalance(sender: TRef[Amount],
amount: Amount): STM[Nothing, Amount] =
debit(sender, amount)
.foldM(
_ => sender.get,
_ => sender.get)
STM - FoldM
def awaitTicket(tref: TRef[Option[Ticket]]): STM[Nothing, Ticket] =
for {
option <- tref.get
ticket <- option match {
case None => STM.retry
case Some(ticket) => STM.succeed(ticket)
}
} yield ticket
STM - Retry
def tripTickets: STM[Nothing, (Ticket, Ticket)] =
awaitTicket(toWarsaw) zip awaitTicket(toHome)
STM - Zip
def bid(price : Amount,
org : TRef[TravelCompany]): STM[Nothing, Ticket] =
for {
v <- org.get
_ <- STM.check(v.availTix.exists(_.price <= price))
ticket = findCheapest(v, price)
_ <- org.update(_.removeTix(ticket))
} yield ticket
STM - Check
STM - Filter
def bid(price : Amount,
org : TRef[TravelCompany]): STM[Nothing, Ticket] =
for {
v <- org.get.filter(_.availTix.exists(_.price <= price))
ticket = findCheapest(v, price)
_ <- org.update(_.removeTix(ticket))
} yield ticket
val trainOrAirplane: STM[Nothing, Ticket] =
bid(25.00, Railway) orElse bid(50.00, Airline)
STM - Choice
def checkIn(passengers: TRef[List[Person]]): STM[Nothing, Person] =
for {
head <- passengers.get.collect { case head :: tail => head }
_ <- passengers.update(_.drop(1))
} yield head
STM - Collect
STM
STM
STM
STM
Composable Easy to Reason About
def transfer(from : TRef[Account],
to : TRef[Account],
amount : Amount): UIO[Unit] =
atomically {
for {
balance <- from.get
_ <- check(balance >= amount)
_ <- from.update(_ - amount)
_ <- to.update(_ + amount)
} yield ()
}
Become a Hero
Semaphore
Thread #2 holds
1 permit
Thread #1 holds
2 permits
Thread #3 waits
for 4 permits
Semaphore
6 permits
Semaphore
7 contributors
11 months+
301 lines of code
Semaphore
type Semaphore = TRef[Int]
Semaphore
def makeSemaphore(n: Int): UIO[Semaphore] =
TRef.make(n).commit
Semaphore
def acquire(semaphore: Semaphore, n: Int): UIO[Unit] =
(for {
value <- semaphore.get
_ <- STM.check(value >= n)
_ <- semaphore.set(value - n)
} yield ()).commit
Semaphore
def acquire(semaphore: Semaphore, n: Int): UIO[Unit] =
(for {
value <- semaphore.get
_ <- STM.check(value >= n)
_ <- semaphore.set(value - n)
} yield ()).commit
Semaphore
def acquire(semaphore: Semaphore, n: Int): UIO[Unit] =
(for {
value <- semaphore.get
_ <- STM.check(value >= n)
_ <- semaphore.set(value - n)
} yield ()).commit
Semaphore
def acquire(semaphore: Semaphore, n: Int): UIO[Unit] =
(for {
value <- semaphore.get
_ <- STM.check(value >= n)
_ <- semaphore.set(value - n)
} yield ()).commit
Semaphore
def release(semaphore: Semaphore, n: Int): UIO[Unit] =
semaphore.update(_ + n).commit
Semaphore
1 author (you!)
10 minutes
8 lines of code
Your Semaphore using ZIO!
Promise
Unset Set
Wait Wait Continue Continue
Promise
7 contributors
11 months+
274 lines of code
Promise
type Promise[A] = TRef[Option[A]]
Promise
def makePromise[A]: UIO[Promise[A]] =
TRef.make(None).commit
Promise
def complete[A](promise: Promise[A], v: A): UIO[Boolean] =
(for {
value <- promise.get
change <- value match {
case Some(_) => STM.succeed(false)
case None => promise.set(Some(v)) *>
STM.succeed(true)
}
} yield change).commit
Promise
def complete[A](promise: Promise[A], v: A): UIO[Boolean] =
(for {
value <- promise.get
change <- value match {
case Some(_) => STM.succeed(false)
case None => promise.set(Some(v)) *>
STM.succeed(true)
}
} yield change).commit
Promise
def complete[A](promise: Promise[A], v: A): UIO[Boolean] =
(for {
value <- promise.get
change <- value match {
case Some(_) => STM.succeed(false)
case None => promise.set(Some(v)) *>
STM.succeed(true)
}
} yield change).commit
Promise
def complete[A](promise: Promise[A], v: A): UIO[Boolean] =
(for {
value <- promise.get
change <- value match {
case Some(_) => STM.succeed(false)
case None => promise.set(Some(v)) *>
STM.succeed(true)
}
} yield change).commit
Promise
def await[A](promise: Promise[A]): UIO[A] =
promise.get.collect { case Some(a) => a }.commit
Promise
1 author (you!)
10 minutes
8 lines of code
Your Promise using ZIO!
Queue
Empty Queue
Capacity: 6
Full Queue
Capacity: 6
Offer
(Continue)
Take
(Wait)
Offer
(Wait)
Take
(Continue)
Queue
4 contributors
9 months+
487 lines of code
Queue
case class Queue[A](
capacity : Int,
tref : TRef[ScalaQueue[A]])
Queue
def makeQueue[A](capacity: Int): UIO[Queue[A]] =
TRef.make(ScalaQueue.empty[A]).commit
.map(Queue(capacity, _))
Queue
def offer[A](queue: Queue[A], a: A): UIO[Unit] =
(for {
q <- queue.tref.get
_ <- STM.check(q.length < queue.capacity)
_ <- queue.tref.update(_ enqueue a)
} yield ()).commit
Queue
def offer[A](queue: Queue[A], a: A): UIO[Unit] =
(for {
q <- queue.tref.get
_ <- STM.check(q.length < queue.capacity)
_ <- queue.tref.update(_ enqueue a)
} yield ()).commit
Queue
def offer[A](queue: Queue[A], a: A): UIO[Unit] =
(for {
q <- queue.tref.get
_ <- STM.check(q.length < queue.capacity)
_ <- queue.tref.update(_ enqueue a)
} yield ()).commit
Queue
def offer[A](queue: Queue[A], a: A): UIO[Unit] =
(for {
q <- queue.tref.get
_ <- STM.check(q.length < queue.capacity)
_ <- queue.tref.update(_ enqueue a)
} yield ()).commit
Queue
def take[A](queue: Queue[A]): UIO[A] =
(for {
q <- queue.tref.get
a <- q.dequeueOption match {
case Some((a, as)) =>
queue.tref.set(as) *> STM.succeed(a)
case _ => STM.retry
}
} yield a).commit
Queue
def take[A](queue: Queue[A]): UIO[A] =
(for {
q <- queue.tref.get
a <- q.dequeueOption match {
case Some((a, as)) =>
queue.tref.set(as) *> STM.succeed(a)
case _ => STM.retry
}
} yield a).commit
Queue
def take[A](queue: Queue[A]): UIO[A] =
(for {
q <- queue.tref.get
a <- q.dequeueOption match {
case Some((a, as)) =>
queue.tref.set(as) *> STM.succeed(a)
case _ => STM.retry
}
} yield a).commit
Queue
def take[A](queue: Queue[A]): UIO[A] =
(for {
q <- queue.tref.get
a <- q.dequeueOption match {
case Some((a, as)) =>
queue.tref.set(as) *> STM.succeed(a)
case _ => STM.retry
}
} yield a).commit
Queue
1 author (you)
14 minutes
13 lines of code
Your Queue using ZIO!
Wrap Up
THANK YOU!
LEARN MORE
github.com/scalaz/scalaz-zio
gitter.im/scalaz/scalaz-zio
FOLLOW US
@jdegoes @wiemzin

Contenu connexe

Tendances

Refactoring Functional Type Classes
Refactoring Functional Type ClassesRefactoring Functional Type Classes
Refactoring Functional Type ClassesJohn De Goes
 
Principled Error Handling with FP
Principled Error Handling with FPPrincipled Error Handling with FP
Principled Error Handling with FPLuka Jacobowitz
 
Testing in the World of Functional Programming
Testing in the World of Functional ProgrammingTesting in the World of Functional Programming
Testing in the World of Functional ProgrammingLuka Jacobowitz
 
Functor, Apply, Applicative And Monad
Functor, Apply, Applicative And MonadFunctor, Apply, Applicative And Monad
Functor, Apply, Applicative And MonadOliver Daff
 
ZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaWiem Zine Elabidine
 
Advanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to FreeAdvanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to FreeLuka Jacobowitz
 
Scalaz 8: A Whole New Game
Scalaz 8: A Whole New GameScalaz 8: A Whole New Game
Scalaz 8: A Whole New GameJohn De Goes
 
Java 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forwardJava 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forwardMario Fusco
 
Post-Free: Life After Free Monads
Post-Free: Life After Free MonadsPost-Free: Life After Free Monads
Post-Free: Life After Free MonadsJohn De Goes
 
"Немного о функциональном программирование в JavaScript" Алексей Коваленко
"Немного о функциональном программирование в JavaScript" Алексей Коваленко"Немного о функциональном программирование в JavaScript" Алексей Коваленко
"Немного о функциональном программирование в JavaScript" Алексей КоваленкоFwdays
 
Flying Futures at the same sky can make the sun rise at midnight
Flying Futures at the same sky can make the sun rise at midnightFlying Futures at the same sky can make the sun rise at midnight
Flying Futures at the same sky can make the sun rise at midnightWiem Zine Elabidine
 
Monad Transformers In The Wild
Monad Transformers In The WildMonad Transformers In The Wild
Monad Transformers In The WildStackMob Inc
 
Quark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & AnalyticsQuark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & AnalyticsJohn De Goes
 
7 Habits For a More Functional Swift
7 Habits For a More Functional Swift7 Habits For a More Functional Swift
7 Habits For a More Functional SwiftJason Larsen
 

Tendances (20)

Refactoring Functional Type Classes
Refactoring Functional Type ClassesRefactoring Functional Type Classes
Refactoring Functional Type Classes
 
Hammurabi
HammurabiHammurabi
Hammurabi
 
Principled Error Handling with FP
Principled Error Handling with FPPrincipled Error Handling with FP
Principled Error Handling with FP
 
Testing in the World of Functional Programming
Testing in the World of Functional ProgrammingTesting in the World of Functional Programming
Testing in the World of Functional Programming
 
ZIO Queue
ZIO QueueZIO Queue
ZIO Queue
 
Berlin meetup
Berlin meetupBerlin meetup
Berlin meetup
 
Functor, Apply, Applicative And Monad
Functor, Apply, Applicative And MonadFunctor, Apply, Applicative And Monad
Functor, Apply, Applicative And Monad
 
ZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in Scala
 
Advanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to FreeAdvanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to Free
 
Pure Future
Pure FuturePure Future
Pure Future
 
Scalaz 8: A Whole New Game
Scalaz 8: A Whole New GameScalaz 8: A Whole New Game
Scalaz 8: A Whole New Game
 
Java 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forwardJava 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forward
 
Post-Free: Life After Free Monads
Post-Free: Life After Free MonadsPost-Free: Life After Free Monads
Post-Free: Life After Free Monads
 
"Немного о функциональном программирование в JavaScript" Алексей Коваленко
"Немного о функциональном программирование в JavaScript" Алексей Коваленко"Немного о функциональном программирование в JavaScript" Алексей Коваленко
"Немного о функциональном программирование в JavaScript" Алексей Коваленко
 
Zio from Home
Zio from Home Zio from Home
Zio from Home
 
Flying Futures at the same sky can make the sun rise at midnight
Flying Futures at the same sky can make the sun rise at midnightFlying Futures at the same sky can make the sun rise at midnight
Flying Futures at the same sky can make the sun rise at midnight
 
Monad Transformers In The Wild
Monad Transformers In The WildMonad Transformers In The Wild
Monad Transformers In The Wild
 
Quark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & AnalyticsQuark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & Analytics
 
Fiber supervision in ZIO
Fiber supervision in ZIOFiber supervision in ZIO
Fiber supervision in ZIO
 
7 Habits For a More Functional Swift
7 Habits For a More Functional Swift7 Habits For a More Functional Swift
7 Habits For a More Functional Swift
 

Similaire à Atomically { Delete Your Actors }

Monadologie
MonadologieMonadologie
Monadologieleague
 
Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303Alex Semin
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with GroovyArturo Herrero
 
Implement the following sorting algorithms Bubble Sort Insertion S.pdf
Implement the following sorting algorithms  Bubble Sort  Insertion S.pdfImplement the following sorting algorithms  Bubble Sort  Insertion S.pdf
Implement the following sorting algorithms Bubble Sort Insertion S.pdfkesav24
 
ES6 patterns in the wild
ES6 patterns in the wildES6 patterns in the wild
ES6 patterns in the wildJoe Morgan
 
b. (10 pts) Implement the rotate left method for AVL trees.c. (10 .pdf
b. (10 pts) Implement the rotate left method for AVL trees.c. (10 .pdfb. (10 pts) Implement the rotate left method for AVL trees.c. (10 .pdf
b. (10 pts) Implement the rotate left method for AVL trees.c. (10 .pdfakanshanawal
 
Functional programming techniques in real-world microservices
Functional programming techniques in real-world microservicesFunctional programming techniques in real-world microservices
Functional programming techniques in real-world microservicesAndrás Papp
 
Mutation testing: Too good to be true? (4Developers)
Mutation testing: Too good to be true? (4Developers)Mutation testing: Too good to be true? (4Developers)
Mutation testing: Too good to be true? (4Developers)Piotr Kubowicz
 
Swift, via "swift-2048"
Swift, via "swift-2048"Swift, via "swift-2048"
Swift, via "swift-2048"Austin Zheng
 
Mutation testing: Too good to be true? (Devoxx)
Mutation testing: Too good to be true? (Devoxx)Mutation testing: Too good to be true? (Devoxx)
Mutation testing: Too good to be true? (Devoxx)Piotr Kubowicz
 
A Playful Introduction to Rx
A Playful Introduction to RxA Playful Introduction to Rx
A Playful Introduction to RxAndrey Cheptsov
 
High-Performance Haskell
High-Performance HaskellHigh-Performance Haskell
High-Performance HaskellJohan Tibell
 
Concurrent Application Development using Scala
Concurrent Application Development using ScalaConcurrent Application Development using Scala
Concurrent Application Development using ScalaSiarhiej Siemianchuk
 

Similaire à Atomically { Delete Your Actors } (20)

Monadologie
MonadologieMonadologie
Monadologie
 
Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303
 
Python Homework Help
Python Homework HelpPython Homework Help
Python Homework Help
 
Clojure workshop
Clojure workshopClojure workshop
Clojure workshop
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with Groovy
 
Clojure functions examples
Clojure functions examplesClojure functions examples
Clojure functions examples
 
Implement the following sorting algorithms Bubble Sort Insertion S.pdf
Implement the following sorting algorithms  Bubble Sort  Insertion S.pdfImplement the following sorting algorithms  Bubble Sort  Insertion S.pdf
Implement the following sorting algorithms Bubble Sort Insertion S.pdf
 
ES6 patterns in the wild
ES6 patterns in the wildES6 patterns in the wild
ES6 patterns in the wild
 
b. (10 pts) Implement the rotate left method for AVL trees.c. (10 .pdf
b. (10 pts) Implement the rotate left method for AVL trees.c. (10 .pdfb. (10 pts) Implement the rotate left method for AVL trees.c. (10 .pdf
b. (10 pts) Implement the rotate left method for AVL trees.c. (10 .pdf
 
Functional programming techniques in real-world microservices
Functional programming techniques in real-world microservicesFunctional programming techniques in real-world microservices
Functional programming techniques in real-world microservices
 
Mutation testing: Too good to be true? (4Developers)
Mutation testing: Too good to be true? (4Developers)Mutation testing: Too good to be true? (4Developers)
Mutation testing: Too good to be true? (4Developers)
 
SDC - Einführung in Scala
SDC - Einführung in ScalaSDC - Einführung in Scala
SDC - Einführung in Scala
 
ddd+scala
ddd+scaladdd+scala
ddd+scala
 
Swift, via "swift-2048"
Swift, via "swift-2048"Swift, via "swift-2048"
Swift, via "swift-2048"
 
Python Tidbits
Python TidbitsPython Tidbits
Python Tidbits
 
Mutation testing: Too good to be true? (Devoxx)
Mutation testing: Too good to be true? (Devoxx)Mutation testing: Too good to be true? (Devoxx)
Mutation testing: Too good to be true? (Devoxx)
 
A Playful Introduction to Rx
A Playful Introduction to RxA Playful Introduction to Rx
A Playful Introduction to Rx
 
Python Homework Help
Python Homework HelpPython Homework Help
Python Homework Help
 
High-Performance Haskell
High-Performance HaskellHigh-Performance Haskell
High-Performance Haskell
 
Concurrent Application Development using Scala
Concurrent Application Development using ScalaConcurrent Application Development using Scala
Concurrent Application Development using Scala
 

Plus de John De Goes

Error Management: Future vs ZIO
Error Management: Future vs ZIOError Management: Future vs ZIO
Error Management: Future vs ZIOJohn De Goes
 
Scalaz Stream: Rebirth
Scalaz Stream: RebirthScalaz Stream: Rebirth
Scalaz Stream: RebirthJohn De Goes
 
Scalaz Stream: Rebirth
Scalaz Stream: RebirthScalaz Stream: Rebirth
Scalaz Stream: RebirthJohn De Goes
 
Orthogonal Functional Architecture
Orthogonal Functional ArchitectureOrthogonal Functional Architecture
Orthogonal Functional ArchitectureJohn De Goes
 
The Design of the Scalaz 8 Effect System
The Design of the Scalaz 8 Effect SystemThe Design of the Scalaz 8 Effect System
The Design of the Scalaz 8 Effect SystemJohn De Goes
 
Streams for (Co)Free!
Streams for (Co)Free!Streams for (Co)Free!
Streams for (Co)Free!John De Goes
 
Halogen: Past, Present, and Future
Halogen: Past, Present, and FutureHalogen: Past, Present, and Future
Halogen: Past, Present, and FutureJohn De Goes
 
All Aboard The Scala-to-PureScript Express!
All Aboard The Scala-to-PureScript Express!All Aboard The Scala-to-PureScript Express!
All Aboard The Scala-to-PureScript Express!John De Goes
 
Getting Started with PureScript
Getting Started with PureScriptGetting Started with PureScript
Getting Started with PureScriptJohn De Goes
 
SlamData - How MongoDB Is Powering a Revolution in Visual Analytics
SlamData - How MongoDB Is Powering a Revolution in Visual AnalyticsSlamData - How MongoDB Is Powering a Revolution in Visual Analytics
SlamData - How MongoDB Is Powering a Revolution in Visual AnalyticsJohn De Goes
 
The Next Great Functional Programming Language
The Next Great Functional Programming LanguageThe Next Great Functional Programming Language
The Next Great Functional Programming LanguageJohn De Goes
 
The Dark Side of NoSQL
The Dark Side of NoSQLThe Dark Side of NoSQL
The Dark Side of NoSQLJohn De Goes
 
First-Class Patterns
First-Class PatternsFirst-Class Patterns
First-Class PatternsJohn De Goes
 
Quirrel & R for Dummies
Quirrel & R for DummiesQuirrel & R for Dummies
Quirrel & R for DummiesJohn De Goes
 
In-Database Predictive Analytics
In-Database Predictive AnalyticsIn-Database Predictive Analytics
In-Database Predictive AnalyticsJohn De Goes
 
Analytics Maturity Model
Analytics Maturity ModelAnalytics Maturity Model
Analytics Maturity ModelJohn De Goes
 
Rise of the scientific database
Rise of the scientific databaseRise of the scientific database
Rise of the scientific databaseJohn De Goes
 

Plus de John De Goes (20)

Error Management: Future vs ZIO
Error Management: Future vs ZIOError Management: Future vs ZIO
Error Management: Future vs ZIO
 
Scalaz Stream: Rebirth
Scalaz Stream: RebirthScalaz Stream: Rebirth
Scalaz Stream: Rebirth
 
Scalaz Stream: Rebirth
Scalaz Stream: RebirthScalaz Stream: Rebirth
Scalaz Stream: Rebirth
 
ZIO Queue
ZIO QueueZIO Queue
ZIO Queue
 
Orthogonal Functional Architecture
Orthogonal Functional ArchitectureOrthogonal Functional Architecture
Orthogonal Functional Architecture
 
The Design of the Scalaz 8 Effect System
The Design of the Scalaz 8 Effect SystemThe Design of the Scalaz 8 Effect System
The Design of the Scalaz 8 Effect System
 
Streams for (Co)Free!
Streams for (Co)Free!Streams for (Co)Free!
Streams for (Co)Free!
 
MTL Versus Free
MTL Versus FreeMTL Versus Free
MTL Versus Free
 
Halogen: Past, Present, and Future
Halogen: Past, Present, and FutureHalogen: Past, Present, and Future
Halogen: Past, Present, and Future
 
All Aboard The Scala-to-PureScript Express!
All Aboard The Scala-to-PureScript Express!All Aboard The Scala-to-PureScript Express!
All Aboard The Scala-to-PureScript Express!
 
Getting Started with PureScript
Getting Started with PureScriptGetting Started with PureScript
Getting Started with PureScript
 
SlamData - How MongoDB Is Powering a Revolution in Visual Analytics
SlamData - How MongoDB Is Powering a Revolution in Visual AnalyticsSlamData - How MongoDB Is Powering a Revolution in Visual Analytics
SlamData - How MongoDB Is Powering a Revolution in Visual Analytics
 
The Next Great Functional Programming Language
The Next Great Functional Programming LanguageThe Next Great Functional Programming Language
The Next Great Functional Programming Language
 
The Dark Side of NoSQL
The Dark Side of NoSQLThe Dark Side of NoSQL
The Dark Side of NoSQL
 
First-Class Patterns
First-Class PatternsFirst-Class Patterns
First-Class Patterns
 
Quirrel & R for Dummies
Quirrel & R for DummiesQuirrel & R for Dummies
Quirrel & R for Dummies
 
In-Database Predictive Analytics
In-Database Predictive AnalyticsIn-Database Predictive Analytics
In-Database Predictive Analytics
 
Analytics Maturity Model
Analytics Maturity ModelAnalytics Maturity Model
Analytics Maturity Model
 
Rise of the scientific database
Rise of the scientific databaseRise of the scientific database
Rise of the scientific database
 
Fun with automata
Fun with automataFun with automata
Fun with automata
 

Dernier

Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentPim van der Noll
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
React Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App FrameworkReact Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App FrameworkPixlogix Infotech
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch TuesdayIvanti
 
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Strongerpanagenda
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxLoriGlavin3
 
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotesMuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotesManik S Magar
 
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS:  6 Ways to Automate Your Data IntegrationBridging Between CAD & GIS:  6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integrationmarketing932765
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxGenerative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxfnnc6jmgwh
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Hiroshi SHIBATA
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPathCommunity
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality AssuranceInflectra
 
Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Farhan Tariq
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityIES VE
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesThousandEyes
 
Scale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterScale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterMydbops
 
Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)Kaya Weers
 

Dernier (20)

Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
React Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App FrameworkReact Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App Framework
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch Tuesday
 
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
 
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotesMuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
 
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS:  6 Ways to Automate Your Data IntegrationBridging Between CAD & GIS:  6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxGenerative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to Hero
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
 
Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a reality
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
 
Scale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterScale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL Router
 
Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)
 

Atomically { Delete Your Actors }

  • 1. atomically { delete your actors } John A. De Goes — @jdegoes Wiem Zine Elabidine — @wiemzin
  • 2. The Bank Heist The Hero Become a Hero!
  • 4.
  • 5.
  • 6.
  • 8.
  • 9.
  • 10. #1
  • 11. #1
  • 12. 12 def transfer(from: Account, to: Account, amount: Amount): Unit = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } }
  • 13. 13 def transfer(from: Account, to: Account, amount: Amount): Unit = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } }
  • 14. 14 def transfer(from: Account, to: Account, amount: Amount): Unit = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } }
  • 15. 15 def transfer(from: Account, to: Account, amount: Amount): Unit = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } }
  • 17. def transfer(from: Account, to: Account, amount: Amount) = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } } def transfer(from: Account, to: Account, amount: Amount) = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } } Thread 1 Thread 2 Race Condition Exploit
  • 18. def transfer(from: Account, to: Account, amount: Amount) = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } } def transfer(from: Account, to: Account, amount: Amount) = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } } Thread 1 Thread 2 Race Condition Exploit
  • 19.
  • 20. 20 class Account { var balance : Amount var accountID : AccountID var name : String val opened : Instant val status : AccountStatus val tpe : AccountType }
  • 21. balance 200,000 accountID 2816157231 ... ... Main Memory balance 200,000 accountID 2816157231 ... ... Core 1 Cache balance 200,000 accountID 2816157231 ... ... Core 2 Cache
  • 22. def transfer(from: Account, to: Account, amount: Amount) = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } } def transfer(from: Account, to: Account, amount: Amount) = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } } Thread 1 Thread 2 Stale Cache Exploit
  • 23.
  • 24. from.balance -= amount 4: getfield #2 7: invokevirtual #3 10: aload_2 11: invokevirtual #3 14: isub 15: invokestatic #4 18: dup_x1 19: putfield #2
  • 25. def transfer(from: Account, to: Account, amount: Amount) = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } } def transfer(from: Account, to: Account, amount: Amount) = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } } Thread 1 Thread 2 Nonatomic Instruction Exploit
  • 26.
  • 27.
  • 28.
  • 29. abstract class Account { trait State { @volatile var balance: BigDecimal = _ } val state: State def modify[A](f: State => A): A = this.synchronized { val result = f(state) this.notifyAll() result } def await(): Unit = this.synchronized { this.wait() } }
  • 30. def transfer(from: Account, to: Account, amount: Amount): Unit = { var loop = true while (loop) { from.modify { state => if (state.balance >= amount.value) { state.balance -= amount.value to.modify(state => state.balance += amount.value) loop = false } else from.await() } }
  • 31. transfer(from, to, amount) transfer(to, from, amount) Thread 1 Thread 2 Deadlock Exploit
  • 32.
  • 33.
  • 34.
  • 35. class Account extends Actor { var balance = Amount.zero var todos = List.empty[(ActorRef, Message)] def receive = { case Deposit(amount) => balance = balance + amount.value sender ! Success(balance) todos.foreach { case (s, m) => self ! m } todos = Nil case v @ Withdraw(amount) => if (balance >= amount.value) { balance = balance - amount.value sender ! Success(balance) } else todos = (sender, v) :: todos case Balance => sender ! Success(balance) } }
  • 36. def transfer(from: ActorRef, to: ActorRef, amount: Amount)(implicit garbage: Timeout): Unit = (from ? Withdraw(amount)).flatMap { _ => to ? Deposit(amount) }
  • 37.
  • 38. for { john <- johnAccount ? Balance wiem <- wiemAccount ? Balance } yield if (wiem.value > john.value) transfer(wiem, cafe, amount) else transfer(john, cafe, amount) $70 $99
  • 39. for { john <- johnAccount ? Balance wiem <- wiemAccount ? Balance } yield if (wiem.value > john.value) transfer(wiem, cafe, amount) else transfer(john, cafe, amount) $70 $6,000,000 $99
  • 40. for { john <- johnAccount ? Balance wiem <- wiemAccount ? Balance } yield if (wiem.value > john.value) transfer(wiem, cafe, amount) else transfer(john, cafe, amount) $70 $6,000,000 $99
  • 41. $70 ~$6m for { john <- johnAccount ? Balance wiem <- wiemAccount ? Balance } yield if (wiem.value > john.value) transfer(wiem, cafe, amount) else transfer(john, cafe, amount) $10 $99
  • 42. $70 -$60 for { john <- johnAccount ? Balance wiem <- wiemAccount ? Balance } yield if (wiem.value > john.value) transfer(wiem, cafe, amount) else transfer(john, cafe, amount) $99
  • 43.
  • 44.
  • 45.
  • 46. 46 def transfer(from : TRef[Account], to : TRef[Account], amount : Amount): UIO[Unit] = atomically { for { balance <- from.get _ <- check(balance >= amount) _ <- from.update(_ - amount) _ <- to.update(_ + amount) } yield () }
  • 47. 47 def transfer(from : TRef[Account], to : TRef[Account], amount : Amount): UIO[Unit] = atomically { for { balance <- from.get _ <- check(balance >= amount) _ <- from.update(_ - amount) _ <- to.update(_ + amount) } yield () }
  • 48. 48 def transfer(from : TRef[Account], to : TRef[Account], amount : Amount): UIO[Unit] = atomically { for { balance <- from.get _ <- check(balance >= amount) _ <- from.update(_ - amount) _ <- to.update(_ + amount) } yield () }
  • 49. 49 def transfer(from : TRef[Account], to : TRef[Account], amount : Amount): UIO[Unit] = atomically { for { balance <- from.get _ <- check(balance >= amount) _ <- from.update(_ - amount) _ <- to.update(_ + amount) } yield () }
  • 50. 50 def transfer(from : TRef[Account], to : TRef[Account], amount : Amount): UIO[Unit] = atomically { for { balance <- from.get _ <- check(balance >= amount) _ <- from.update(_ - amount) _ <- to.update(_ + amount) } yield () }
  • 51. 51 def transfer(from : TRef[Account], to : TRef[Account], amount : Amount): UIO[Unit] = atomically { for { balance <- from.get _ <- check(balance >= amount) _ <- from.update(_ - amount) _ <- to.update(_ + amount) } yield () }
  • 52.
  • 54. STM: Software Transactional Memory Provides the ability to atomically commit a series of reads and writes to transactional memory when a set of conditions is satisfied. STM
  • 55. STM ...Op 2Op 1 Op n Final State Initial State commit failure - rollback retry - rollback complete complete
  • 56. STM STM[E, A] A transaction, which models reads & writes, and can fail, retry, or succeed. TRef[A] A transactional reference, which is read & written inside STM transactions.
  • 57. STM[E, A] Succeed with a value of type A Fail with an error of type E STM
  • 58. STM STM[E, A] A transaction, which models reads & writes, and can fail, retry, or succeed. TRef[A] A transactional reference, which is read & written inside STM transactions.
  • 61. trait TRef[A] { val get: STM[Nothing, A] def set(newValue: A): STM[Nothing, Unit] def update(f: A => A): STM[Nothing, A] def modify[B](f: A => (B, A)): STM[Nothing, B] } object TRef { def make[A](a: A): STM[Nothing, TRef[A]] } TRef
  • 62. trait TRef[A] { val get: STM[Nothing, A] def set(newValue: A): STM[Nothing, Unit] def update(f: A => A): STM[Nothing, A] def modify[B](f: A => (B, A)): STM[Nothing, B] } object TRef { def make[A](a: A): STM[Nothing, TRef[A]] } TRef
  • 63. trait TRef[A] { val get: STM[Nothing, A] def set(newValue: A): STM[Nothing, Unit] def update(f: A => A): STM[Nothing, A] def modify[B](f: A => (B, A)): STM[Nothing, B] } object TRef { def make[A](a: A): STM[Nothing, TRef[A]] } TRef
  • 64. trait TRef[A] { val get: STM[Nothing, A] def set(newValue: A): STM[Nothing, Unit] def update(f: A => A): STM[Nothing, A] def modify[B](f: A => (B, A)): STM[Nothing, B] } object TRef { def make[A](a: A): STM[Nothing, TRef[A]] } TRef
  • 65. trait TRef[A] { val get: STM[Nothing, A] def set(newValue: A): STM[Nothing, Unit] def update(f: A => A): STM[Nothing, A] def modify[B](f: A => (B, A)): STM[Nothing, B] } object TRef { def make[A](a: A): STM[Nothing, TRef[A]] } TRef
  • 66. trait STM[+E, +A] { def commit: IO[E, A] = STM.atomically { this } } object STM { def atomically[E, A](stm: STM[E, A]): IO[E, A] } STM - Commit
  • 67. val hello: STM[Nothing, String] = STM.succeed("Welcome to Scalar") STM - Succeed
  • 68. val sumBalances: STM[Nothing, Int] = balance1.get.flatMap(a => balance2.get.map(b => a + b)) STM - map & flatMap
  • 69. val sumBalances: STM[Nothing, Int] = for { a <- balance1.get b <- balance2.get } yield a + b STM - map & flatMap
  • 70. STM - Fail def debit(sender: TRef[Amount], amount: Amount): STM[String, Amount] = for { balance <- sender.update(_ - amount) _ <- if (balance < 0) STM.fail("Insufficient funds") else STM.succeed(()) } yield balance
  • 71. def debitSuccess(sender: TRef[Amount], amount: Amount): STM[Nothing, Boolean] = debit(sender, amount).fold(_ => false, _ => true) STM - Fold
  • 72. def debitWithBalance(sender: TRef[Amount], amount: Amount): STM[Nothing, Amount] = debit(sender, amount) .foldM( _ => sender.get, _ => sender.get) STM - FoldM
  • 73. def awaitTicket(tref: TRef[Option[Ticket]]): STM[Nothing, Ticket] = for { option <- tref.get ticket <- option match { case None => STM.retry case Some(ticket) => STM.succeed(ticket) } } yield ticket STM - Retry
  • 74. def tripTickets: STM[Nothing, (Ticket, Ticket)] = awaitTicket(toWarsaw) zip awaitTicket(toHome) STM - Zip
  • 75. def bid(price : Amount, org : TRef[TravelCompany]): STM[Nothing, Ticket] = for { v <- org.get _ <- STM.check(v.availTix.exists(_.price <= price)) ticket = findCheapest(v, price) _ <- org.update(_.removeTix(ticket)) } yield ticket STM - Check
  • 76. STM - Filter def bid(price : Amount, org : TRef[TravelCompany]): STM[Nothing, Ticket] = for { v <- org.get.filter(_.availTix.exists(_.price <= price)) ticket = findCheapest(v, price) _ <- org.update(_.removeTix(ticket)) } yield ticket
  • 77. val trainOrAirplane: STM[Nothing, Ticket] = bid(25.00, Railway) orElse bid(50.00, Airline) STM - Choice
  • 78. def checkIn(passengers: TRef[List[Person]]): STM[Nothing, Person] = for { head <- passengers.get.collect { case head :: tail => head } _ <- passengers.update(_.drop(1)) } yield head STM - Collect
  • 79. STM STM STM STM Composable Easy to Reason About def transfer(from : TRef[Account], to : TRef[Account], amount : Amount): UIO[Unit] = atomically { for { balance <- from.get _ <- check(balance >= amount) _ <- from.update(_ - amount) _ <- to.update(_ + amount) } yield () }
  • 81. Semaphore Thread #2 holds 1 permit Thread #1 holds 2 permits Thread #3 waits for 4 permits Semaphore 6 permits
  • 84. Semaphore def makeSemaphore(n: Int): UIO[Semaphore] = TRef.make(n).commit
  • 85. Semaphore def acquire(semaphore: Semaphore, n: Int): UIO[Unit] = (for { value <- semaphore.get _ <- STM.check(value >= n) _ <- semaphore.set(value - n) } yield ()).commit
  • 86. Semaphore def acquire(semaphore: Semaphore, n: Int): UIO[Unit] = (for { value <- semaphore.get _ <- STM.check(value >= n) _ <- semaphore.set(value - n) } yield ()).commit
  • 87. Semaphore def acquire(semaphore: Semaphore, n: Int): UIO[Unit] = (for { value <- semaphore.get _ <- STM.check(value >= n) _ <- semaphore.set(value - n) } yield ()).commit
  • 88. Semaphore def acquire(semaphore: Semaphore, n: Int): UIO[Unit] = (for { value <- semaphore.get _ <- STM.check(value >= n) _ <- semaphore.set(value - n) } yield ()).commit
  • 89. Semaphore def release(semaphore: Semaphore, n: Int): UIO[Unit] = semaphore.update(_ + n).commit
  • 90. Semaphore 1 author (you!) 10 minutes 8 lines of code Your Semaphore using ZIO!
  • 91. Promise Unset Set Wait Wait Continue Continue
  • 93. Promise type Promise[A] = TRef[Option[A]]
  • 95. Promise def complete[A](promise: Promise[A], v: A): UIO[Boolean] = (for { value <- promise.get change <- value match { case Some(_) => STM.succeed(false) case None => promise.set(Some(v)) *> STM.succeed(true) } } yield change).commit
  • 96. Promise def complete[A](promise: Promise[A], v: A): UIO[Boolean] = (for { value <- promise.get change <- value match { case Some(_) => STM.succeed(false) case None => promise.set(Some(v)) *> STM.succeed(true) } } yield change).commit
  • 97. Promise def complete[A](promise: Promise[A], v: A): UIO[Boolean] = (for { value <- promise.get change <- value match { case Some(_) => STM.succeed(false) case None => promise.set(Some(v)) *> STM.succeed(true) } } yield change).commit
  • 98. Promise def complete[A](promise: Promise[A], v: A): UIO[Boolean] = (for { value <- promise.get change <- value match { case Some(_) => STM.succeed(false) case None => promise.set(Some(v)) *> STM.succeed(true) } } yield change).commit
  • 99. Promise def await[A](promise: Promise[A]): UIO[A] = promise.get.collect { case Some(a) => a }.commit
  • 100. Promise 1 author (you!) 10 minutes 8 lines of code Your Promise using ZIO!
  • 101. Queue Empty Queue Capacity: 6 Full Queue Capacity: 6 Offer (Continue) Take (Wait) Offer (Wait) Take (Continue)
  • 103. Queue case class Queue[A]( capacity : Int, tref : TRef[ScalaQueue[A]])
  • 104. Queue def makeQueue[A](capacity: Int): UIO[Queue[A]] = TRef.make(ScalaQueue.empty[A]).commit .map(Queue(capacity, _))
  • 105. Queue def offer[A](queue: Queue[A], a: A): UIO[Unit] = (for { q <- queue.tref.get _ <- STM.check(q.length < queue.capacity) _ <- queue.tref.update(_ enqueue a) } yield ()).commit
  • 106. Queue def offer[A](queue: Queue[A], a: A): UIO[Unit] = (for { q <- queue.tref.get _ <- STM.check(q.length < queue.capacity) _ <- queue.tref.update(_ enqueue a) } yield ()).commit
  • 107. Queue def offer[A](queue: Queue[A], a: A): UIO[Unit] = (for { q <- queue.tref.get _ <- STM.check(q.length < queue.capacity) _ <- queue.tref.update(_ enqueue a) } yield ()).commit
  • 108. Queue def offer[A](queue: Queue[A], a: A): UIO[Unit] = (for { q <- queue.tref.get _ <- STM.check(q.length < queue.capacity) _ <- queue.tref.update(_ enqueue a) } yield ()).commit
  • 109. Queue def take[A](queue: Queue[A]): UIO[A] = (for { q <- queue.tref.get a <- q.dequeueOption match { case Some((a, as)) => queue.tref.set(as) *> STM.succeed(a) case _ => STM.retry } } yield a).commit
  • 110. Queue def take[A](queue: Queue[A]): UIO[A] = (for { q <- queue.tref.get a <- q.dequeueOption match { case Some((a, as)) => queue.tref.set(as) *> STM.succeed(a) case _ => STM.retry } } yield a).commit
  • 111. Queue def take[A](queue: Queue[A]): UIO[A] = (for { q <- queue.tref.get a <- q.dequeueOption match { case Some((a, as)) => queue.tref.set(as) *> STM.succeed(a) case _ => STM.retry } } yield a).commit
  • 112. Queue def take[A](queue: Queue[A]): UIO[A] = (for { q <- queue.tref.get a <- q.dequeueOption match { case Some((a, as)) => queue.tref.set(as) *> STM.succeed(a) case _ => STM.retry } } yield a).commit
  • 113. Queue 1 author (you) 14 minutes 13 lines of code Your Queue using ZIO!
  • 114.