Daniela Sfregola
October 31, 2019
720

# Scala IO 2019 - FP: The Good, The Bad and The Ugly

You are about to fall in love with Functional Programming, if not already. You are going to learn the good parts that are going to make your day-to-day life easier. But since nobody is perfect - not even FP -, you are also going to see its bad and ugly parts, and you'll discover how to deal with them: from learning challenges to performance issues on the JVM.

October 31, 2019

## Transcript

IO 2019
2. ### Hellooooo • Italian living in London UK • Former Java

Developer • Scala Lover
3. ### • Rome, Cinecitta'   23 December 1966 • Director  Sergio

Leone • Music  Ennio Morricone
4. ### Everything in Life • Good Parts  the bits that we

like • Bad Parts  the traps to avoid • Ugly Parts  the parts that we need to live with

7. ### Immutability private var i: Int = 0 while (i <

10) { // do stuff here i = i + 1 } OOP
8. ### Immutability private var i: Int = 0 while (i <

10) { // do stuff here i = i + 1 } OOP (0 until 10).foreach { i => // do stuff here } FP
9. ### Immutability private var i: Int = 0 while (i <

10) { i = i * 2 println(i) i = i + 1 } OOP (0 until 10).foreach { i => println(i * 2) } FP

} Impure
11. ### Purity def foo(s: String): Unit = { // implementation here

} Impure def foo(s: String): Int = { // implementation here } Pure

17. ### You do not need to know Category Theory to write

good   Functional code

Endofunctors

28. ### Case Class to Array def toArray(product: Product): Array[Any] = {

product // Product .productIterator // Iterator[Any] .toArray // Array[Any] } FP
29. ### Case Class to Array def toArray(product: Product): Array[Any] = {

product // Product .productIterator // Iterator[Any] .toArray // Array[Any] } def toArray(product: Product): Array[Any] = { val size = product.productArity val arr = new Array[Any](size) var i = 0 while (i < size) { arr(i) = product.productElement(i) i = i + 1 } arr } FP OOP
30. ### Benchmarking* import com.danielasfregola.randomdatagenerator.RandomDataGenerator._ def avgRunTime[A](f: => A, n: Int =

1000): Double = { val start = Instant.now.toEpochMilli (0 until n).foreach(_ => f) val end = Instant.now.toEpochMilli val diff = end - start diff / n.toDouble } case class BigExample(f1: String, f2: Int, f3: Long, f4: Char, f5: String, f6: String, f7: Int, f8: Long, f9: Char, f10: String, f11: String, f12: Int, f13: Long, f14: Char, f15: String, f16: String, f17: Int, f18: Long, f19: Char, f20: String, f21: String, f22: Int, f23: Long, f24: Char, f25: String, f26: String, f27: Int, f28: Long, f29: Char, f30: String) val big = random[BigExample] avgRunTime(toArrayFP(big)) avgRunTime(toArrayOOP(big)) *not a serious benchmarking, executed on my laptop
31. ### Benchmarking* import com.danielasfregola.randomdatagenerator.RandomDataGenerator._ def avgRunTime[A](f: => A, n: Int =

1000): Double = { val start = Instant.now.toEpochMilli (0 until n).foreach(_ => f) val end = Instant.now.toEpochMilli val diff = end - start diff / n.toDouble } case class BigExample(f1: String, f2: Int, f3: Long, f4: Char, f5: String, f6: String, f7: Int, f8: Long, f9: Char, f10: String, f11: String, f12: Int, f13: Long, f14: Char, f15: String, f16: String, f17: Int, f18: Long, f19: Char, f20: String, f21: String, f22: Int, f23: Long, f24: Char, f25: String, f26: String, f27: Int, f28: Long, f29: Char, f30: String) val big = random[BigExample] avgRunTime(toArrayFP(big)) avgRunTime(toArrayOOP(big)) *not a serious benchmarking, executed on my laptop toArrayOOP avg execution: 0.002 ms toArrayFP avg execution: 0.028 ms
32. ### JVM and FP do not always go along... OOP version

is much faster than the FP one!
33. ### My ideal implementation of map function for List[A] final override

def map[B](f: A => B): List[B] = { @tailrec def loop(l: List[A], res: List[B]): List[B] = { l match { case head :: tail => loop(tail, res :+ f(head)) case Nil => res } } loop(this, res = Nil) }
34. ### The real implementation of map function for List[A]* final override

def map[B](f: A => B): List[B] = { if (this eq Nil) Nil else { val h = new ::[B](f(head), Nil) var t: ::[B] = h var rest = tail while (rest ne Nil) { val nx = new ::(f(rest.head), Nil) t.next = nx t = nx rest = rest.tail } releaseFence() h } } *scala 2.13.0
35. ### If you have a really good reason, break the rules!

...but keep the ugly bits isolated

39. ### Not even Scala is perfect... • Slow Compiler • pipelining

compilation by Jason Zaugg • zinc by Eugene Yokota • Tooling • bloop by Jorge Vicente Cantero • metals by Ólafur Páll Geirsson
40. ### Thank You! •Twitter: @DanielaSfregola •Blog: danielasfregola.com •Book: Get Programming with

Scala  by Manning