Skip to content

Instantly share code, notes, and snippets.

@LMnet
Created February 9, 2019 08:14
Show Gist options
  • Save LMnet/890a368c4f8c074dfaebfa26f3564fa1 to your computer and use it in GitHub Desktop.
Save LMnet/890a368c4f8c074dfaebfa26f3564fa1 to your computer and use it in GitHub Desktop.
LazyFuture example for pragmatic fp talk
package monix.eval
import scala.concurrent.{Await, ExecutionContext, Future}
import scala.concurrent.duration._
object Test extends App {
object LazyFuture {
def delay[A](body: => A): LazyFuture[A] = {
new LazyFuture[A](ec => Future(body)(ec))
}
def fromFuture[A](future: => Future[A]): LazyFuture[A] = {
new LazyFuture[A](_ => future)
}
}
class LazyFuture[A] private (val run: ExecutionContext => Future[A]) { self =>
def map[B](f: A => B): LazyFuture[B] = {
new LazyFuture[B]((ec: ExecutionContext) => {
self.run(ec).map(f)(ec)
})
}
def flatMap[B](f: A => LazyFuture[B]): LazyFuture[B] = {
new LazyFuture[B]((ec: ExecutionContext) => {
self.run(ec).flatMap { a =>
f(a).run(ec)
}(ec)
})
}
def par[B](that: LazyFuture[B]): LazyFuture[(A, B)] = {
new LazyFuture[(A, B)]((ec: ExecutionContext) => {
val selfStarted = self.run(ec)
val thatStarted = that.run(ec)
selfStarted.flatMap { selfRes =>
thatStarted.map { thatRes =>
(selfRes, thatRes)
}(ec)
}(ec)
})
}
}
implicit val ec: ExecutionContext = ExecutionContext.Implicits.global
def future1() = Future { println(1); 1 }
def future2() = Future { println(2); 2 }
def lazyFuture1() = LazyFuture.delay { println(1); 1 }
def lazyFuture2() = LazyFuture.delay { println(2); 2 }
def futureTest: Future[Int] = {
for {
res1 <- future1()
res2 <- future2()
} yield {
val res = res1 + res2
println(res)
res
}
}
def futureTestRtDef: Future[Int] = {
future1().flatMap(_ => future1())
}
def futureTestRtVal: Future[Int] = {
val future = future1()
future.flatMap(_ => future)
}
def futureTestPar: Future[Int] = {
val future1val = future1()
val future2val = future2()
for {
res1 <- future1val
res2 <- future2val
} yield {
val res = res1 + res2
println(res)
res
}
}
def lazyFutureTest: Future[Int] = {
val lazyFuture = for {
res1 <- lazyFuture1()
res2 <- lazyFuture2()
} yield {
val res = res1 + res2
println(res)
res
}
lazyFuture.run(ec)
}
def lazyFutureTestPar: Future[Int] = {
val future1started = lazyFuture1()
val future2started = lazyFuture2()
val lazyFuture = for {
res1 <- future1started
res2 <- future2started
} yield {
val res = res1 + res2
println(res)
res
}
lazyFuture.run(ec)
}
def lazyFutureTestParFixed: Future[Int] = {
val lazyFuture = (lazyFuture1() par lazyFuture2()).map { case (res1, res2) =>
val res = res1 + res2
println(res)
res
}
lazyFuture.run(ec)
}
def lazyFutureTestRtDef: Future[Int] = {
lazyFuture1().flatMap(_ => lazyFuture1()).run(ec)
}
def lazyFutureTestRtVal: Future[Int] = {
val future = lazyFuture1()
future.flatMap(_ => future).run(ec)
}
println("Future sequential test")
Await.ready(futureTest, 1.second)
println("Future parallel test")
Await.ready(futureTestPar, 1.second)
println("LazyFuture sequential test")
Await.ready(lazyFutureTest, 1.second)
println("LazyFuture parallel test")
Await.ready(lazyFutureTestPar, 1.second)
println("LazyFuture parallel fixed test")
Await.ready(lazyFutureTestParFixed, 1.second)
println("Future RT test def")
Await.ready(futureTestRtDef, 1.second)
println("Future RT test val")
Await.ready(futureTestRtVal, 1.second)
println("LazyFuture RT test def")
Await.ready(lazyFutureTestRtDef, 1.second)
println("LazyFuture RT test val")
Await.ready(lazyFutureTestRtVal, 1.second)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment