# Funtional Concurrency in Scala 101

## Plan

• Brief Overview
• Introduction to Functional Programming
• Introduction to Concurrency (with FP!)
• Exercises

## Schedule

9.00 - 10:30 workshop
10:30 - 11:00 break
11:00 - 12:30 workshop
12:30 - 14:00 lunch break
14:00 - 15:30 workshop
15:30 - 16:00 break
16:00 - 17:00 workshop

• Couple of concurrent puzzles for a warm up
• Using newly acquired skills in real use case

## Before we begin...

``````git clone git@github.com:Avasil/fp-concurrency-101.git
or https://github.com/Avasil/fp-concurrency-101.git

git checkout exercises

sbt exercises/compile
sbt client/fastOptJS
sbt server/compile``````

## Functional Programming

• Programming with pure, referentially transparent functions
• Replacing an expression by its bound value doesn't alter the behavior of your program
• Lawful, algebraic structures

## Benefits

• Consistent, known behavior
• Compositionality
• Easy refactoring and optimization rules

## What prevents composition?

• Connected sequence
• Leaky abstraction
• Side effects!

## Side effects

Source of example:

"Rúnar Óli Bjarnason - Composing Programs"

``````class Cafe {
def buyCoffee(cc: CreditCard): Coffee = {
val cup = new Coffee()
cc.charge(cup.price)
cup
}
}``````

## Side effects

Source of example:

"Rúnar Óli Bjarnason - Composing Programs"

``````class Cafe {
def buyCoffee(cc: CreditCard): (Coffee, Charge) = {
val cup = new Coffee()
(cup, new Charge(cc, cup.price))
}
}``````

## So how to write pure functions?

``````val a: Int = 10
val b: Int = a + a // 20

val c: Int = 10 + 10 // 20``````
``````val r = scala.util.Random

val a: Int = r.nextInt // 7
val b: Int = a + a     // 7 + 7

val c: Int = r.nextInt + r.nextInt // 7 + 5``````

## So how to write pure functions?

``````import monix.eval.Task
import cats.implicits._

val r = scala.util.Random
// when run, generates 7
a.runSyncUnsafe // 7

val b: Task[Int] = (a, a).mapN(_ + _)
b.runSyncUnsafe // 7 + 5

c.runSyncUnsafe // 7 + 5

val d: Task[Int] = a.map(x => x + x)
d.runSyncUnsafe // 7 + 7``````

## Referential Transparency - Benefits

• Local reasoning
• Representing the program as value

Check out great explanations there:

## Concurrency

Doing things interleaved

## Parallelism

Doing things at the same time to finish faster

## Concurrency on JVM

Map 1:1 to OS native threads which means we can execute up to N threads in parallel (N = number of cores)

## Context Switch

Before a thread can start doing work, the OS needs to store state of earlier task, restore the new one etc.

## Concurrency on JVM

Takes care of creating and reusing threads, distributing work

Nothing else can be run on blocked thread, resources are wasted.

Tasks are interrupted to allow other tasks to run. Guarantees that each task will get its own "slice" of time.

Tasks voluntarily yield control to the scheduler.

## Monix

• Scala / Scala.js library for composing asynchronous programs
• Lots of cool data types such as Task, Observable, ConcurrentQueue and many more
• Purely functional API
• Cats-Effect integration

• Lazily evaluated
• Lots of concurrency related features
• Error Handling
• Cancelation
• Parallelism
• Resource Safety
• ... and it composes like a charm!

## Basic Usage

``````import monix.eval.Task

// nothing happens yet, it's just a description
// of evaluation that will produce `Unit`, end
// with error or never complete
for {
} yield ()

// prints "hello!" twice
program.runSyncUnsafe()``````
``````import monix.eval.Task
import cats.syntax.flatmap._

``````import monix.eval.Task
import scala.concurrent.duration._

// waits 100 millis (without blocking any Thread!)
// then prints "woke up"

// never finishes

## Error Handling

``````import monix.eval.Task

for {
} yield 42

// A
// Exception in thread "main" java.lang.Exception: B
program.runSyncUnsafe

// A
// Process finished with exit code 0
program.attempt

safeProgram.runSyncUnsafe``````
``````// will print A, B and C
for {
// in case of error executes the Task in argument
} yield 42
``````

## Error Handling

``````def retryBackoff[A](source: Task[A])
(maxRetries: Int, delay: FiniteDuration): Task[A] = {
source.onErrorHandleWith { ex =>
if (maxRetries > 0)
retryBackoff(source)(maxRetries - 1, delay * 2)
.delayExecution(delay)
else
}
}``````

## Parallelism

``````import monix.eval.Task
import cats.implicits._

// using Parallel type class instance from Cats
``````val taskInParallel: Task[Unit] =
for {
// run in "background"
// wait for ioa result
_ <- fibA.join
_ <- fibB.join
} yield ()

// run both in parallel
// and cancel the loser

## Scheduler

• Configurable Execution Model
• Tracing Scheduler (for TaskLocal support)
• Test Scheduler that can simulate passing time

## Scheduler

``````  import monix.execution.schedulers.TestScheduler
import scala.concurrent.duration._

(maxRetries: Int, delay: FiniteDuration): Task[A] = {
source.onErrorHandleWith { ex =>
if (maxRetries > 0)
retryBackoff(source)(maxRetries - 1, delay * 2)
.delayExecution(delay)
else
}
}

val sc = TestScheduler()

println(f.value) // None
sc.tick(10.hours)
println(f.value) // None
sc.tick(1000.days)
println(f.value) // Some(Failure(java.lang.Exception: boom))``````

## Observable

• Inspired by RxJava / ReactiveX
• Push-based streaming with backpressure
• (mostly) Purely functional API

See Alex Nedelcu (author of Monix) presentation for origins: https://monix.io/presentations/2018-tale-two-monix-streams.html

## Observable

``````trait Observable[+A] {
def subscribe(o: Observer[A]): Cancelable
}

trait Observer[-T] {
def onNext(elem: T): Future[Ack]

def onError(ex: Throwable): Unit

def onComplete(): Unit
}``````

## Observable

``````val list: Observable[Long] =
Observable.range(0, 1000)
.take(100)
.map(_ * 2)

list.foldLeftL(0L)(_ + _)``````
``````val task: Task[List[Int]] =
for {
// feeds queue in the background
_         <- runProducer(queue).start
list      <- Observable
.repeatEvalF(queue.poll())
.throttleLast(150.millis)
.takeWhile(_ > 100)
.toListL
} yield list``````

## Observable

``````import monix.eval.Task
import monix.execution.schedulers.TestScheduler
import monix.reactive.Observable

import scala.concurrent.duration._

// using `TestScheduler` to manipulate time
implicit val sc = TestScheduler()

Observable
.intervalWithFixedDelay(2.second)
.foreachL(println)
}

stream.runToFuture(sc)

sc.tick(2.second) // prints 0
sc.tick(4.second) // prints 1
sc.tick(4.second) // prints 2
sc.tick(4.second) // prints 3``````

## Concurrent Data Structures

• cats-effect and monix.catnap provide several purely functional data structures for sharing state and synchronization

## cats.effect.concurrent.Ref

Purely functional wrapper for AtomicRef. Allows for safe concurrent access and mutation but preserves referential transparency.

``````abstract class Ref[F[_], A] {
def get: F[A]
def set(a: A): F[Unit]
def modify[B](f: A => (A, B)): F[B]
// ... and more
}``````

## cats.effect.concurrent.Ref

``````import monix.eval.Task
import cats.effect.concurrent.Ref

ref.modify(list => (s :: list, ()))

for {
_ <- stringsRef.flatMap(put(_, "Scala"))
element <- stringsRef.flatMap(take)
} yield println(element)

program.runSyncUnsafe() // prints None``````

## cats.effect.concurrent.Ref

``````val program: Task[Unit] =
for {
ref <- stringsRef
_ <- put(ref, "Scala")
element <- take(ref)
} yield println(element)

program.runSyncUnsafe() // prints "Some(Scala)"``````
• The only way to share a state is to pass it as a parameter. :)

## cats.effect.concurrent.Deferred

``````abstract class Deferred[F[_], A] {
def get: F[A]
def complete(a: A): F[Unit]
}``````
``````val program =
for {
_           <- runImportantService(healthcheck).start
} yield ()

// somewhere in ImportantService
stopRunning.complete(())``````

By Piotr Gawryś

• 710