Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ScalaBase 2021- FP: the Good, the Bad, the Ugly

ScalaBase 2021- FP: the Good, the Bad, 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.

Daniela Sfregola

May 14, 2021
Tweet

More Decks by Daniela Sfregola

Other Decks in Programming

Transcript

  1. FP
    The Good,
    the Bad and the Ugly
    @DanielaSfregola

    Scalabase 2021

    View Slide

  2. Hellooooo
    • Software Engineer 

    living in London UK

    • Former Java Developer

    • Scala Lover ❤

    • OS Maintainer

    • Author of 

    "Get Programming with Scala"
    by Manning


    35% OFF with code "ctwscalabase21"

    View Slide

  3. • Rome, Cinecitta' 

    23 December 1966

    • Director

    Sergio Leone

    • Music

    Ennio Morricone

    View Slide

  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

    View Slide

  5. FP: The Good

    View Slide

  6. Increased
    Productivity

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  10. RTness
    Totality
    Purity
    +
    =

    View Slide

  11. Referential Transparent
    same input same output

    Totality
    always return a value

    View Slide

  12. Is this Pure?
    import java.time.ZonedDateTime
    def plusDays(n: Int): ZonedDateTime =
    ZonedDateTime.now().plusDays(n)
    - Referentially Transparent?
    - Total?

    View Slide

  13. Is this Pure?
    import java.time.ZonedDateTime
    def plusDays(n: Int): ZonedDateTime =
    ZonedDateTime.now().plusDays(n)
    - Referentially Transparent? ⛔
    - Total? ✅

    View Slide

  14. Is this Pure?
    def div(a: Int, b: Int): Int = a / b
    - Referentially Transparent?
    - Total?

    View Slide

  15. Is this Pure?
    def div(a: Int, b: Int): Int = a / b
    - Referentially Transparent? ✅
    - Total? ⛔

    View Slide

  16. Is this Pure?
    def sum(a: Int, b: Int): Int = a + b
    - Referentially Transparent?
    - Total?

    View Slide

  17. Is this Pure?
    def sum(a: Int, b: Int): Int = a + b
    - Referentially Transparent? ✅
    - Total? ✅

    View Slide

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

    View Slide

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

    View Slide

  20. Purity
    Composability

    View Slide

  21. Puzzle Coding!
    from https://scalameta.org/metals/
    Metals

    View Slide

  22. FP: The Bad

    View Slide

  23. Learning Curve

    View Slide

  24. Functional
    Programming

    != 

    Categorical
    Programming

    View Slide

  25. You do not need to know
    Category Theory
    to write good 

    Functional code

    View Slide

  26. ...but Monads are
    EASY!

    View Slide

  27. A Monad is just
    a Monoid
    in the Category of
    Endofunctors

    View Slide

  28. Monads are like

    Burritos
    from https://twitter.com/monadburritos/status/915624691829587968

    View Slide

  29. Is Lasagna a Monad?

    View Slide

  30. The importance of
    talks and tutorials
    for Beginners

    View Slide

  31. The Rock Star
    Developer Syndrome

    View Slide

  32. The Rock Star Developer
    from https://twitter.com/honeypotio/status/689811823281991681

    View Slide

  33. Be a Leader
    not a "Rock Star"

    View Slide

  34. FP: The Ugly

    View Slide

  35. Knowing when to
    break the rules

    View Slide

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

    View Slide

  37. 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

    View Slide

  38. 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

    View Slide

  39. 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

    View Slide

  40. JVM and FP
    do not always go along...
    OOP version
    is much faster than the
    FP one!

    View Slide

  41. 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)
    }

    View Slide

  42. 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

    View Slide

  43. If you have a really good reason,
    break the rules!
    ...but keep the ugly bits isolated

    View Slide

  44. Thank You!
    •Twitter: @DanielaSfregola

    •"Get Programming with Scala" 

    by Manning


    35% OFF with code "ctwscalabase21"

    View Slide