After 10 years of Object Orientated Java, 2 years of Functional Programming in Scala was enough to convince me that I could never switch back. But why? The answer is simple: Functional Scala lets you think less. It reduces the number of moving parts you need to hold in your head, lets you stay focussed and saves your mental stack from overflowing.
In this talk I'll show you how to stop treating Scala as a better Java and start exploring the world of Functional Programming. I'll use code examples to demonstrate a four step path that'll let you ease yourself into the world of Functional Programming while continuing to deliver production quality code.
With each step we'll learn a new technique, and understand how it leaves you with less to think about: Hopefully this talk will convince you that Functional Scala leads to code that's easier to hold in your head, and leave you excited about learning a new paradigm.
20. Convert divide to a total function
case class DivisionError(e: String)
def divide(a: Int, b: Int): Either[DivisionError, Int] = {
if( b == 0) Left(DivisionError("/ by zero"))
Right(a / b)
}
26. Recap: Function signatures
• Total functions have a corresponding
output value to each input value
• Pure functions have no side effects
• Enrich your signature with Container
types
35. How many implementation does
this function have?
def foo[A](a: A): Int = 1
def foo[A](a: A): Int = 2
def foo[A](a: A): Int = 3
def foo[A](a: A): Int = 4
41. Encoding data using Sum Types
sealed trait Developer
case class DevOps(name: String) extends Developer
case class FullStack(name: String, salary: Int) extends Developer
case class ML(name: String, salary: Long) extends Developer
42. Exhaustiveness Checking on ADTs
scala> def sayHi(d: Developer) = d match {
|
| case DevOps(n) => s"Hi $n !"
|
| case FullStack(n, _) => s"Hi $n !"
|
| }
<console>:17: warning: match may not be exhaustive.
It would fail on the following input: ML(_, _)
def sayHi(d: Developer) = d match {
^
sayHi: (d: Developer)String
43. String email or id?
case class User(
id: String,
email: String,
created: Long
)
def loadUser(user: String): User = ???
44. Encode your domain with Value
classes
case class Id(id: String) extends AnyVal
case class Email(email: String) extends AnyVal
case class TimeStamp(ts: Long) extends AnyVal
case class User(id: Id, email: Email, created: TimeStamp)
def loadUser(user: Email): User = ???
45. Recap: ADTs / Value classes
• ADTs encode immutable data
• Value classes let you add domain
knowledge
69. combineAll is a derived function
trait Monoid[A] {
def empty: A
def combine(x: A, y: A): A
def combineAll(as: List[A]): A =
as.foldLeft(empty)(combine)
}
71. Recap: Functional Patterns
• Functional patterns are encoded as typecalsses
• As opposed to Design patterns, functional
patterns are encoded as libraries like cats
• They come with free implementations
• Ecosystem of libraries working with these
patterns
72. One very important thing
• As opposed to frameworks, functional
patterns knowledge does not get old
• You can carry with you through your career,
regardless of languages or platforms
• Some languages even support them out of
the box λ
73. Summary
• Function Signatures with total/pure
functions and container types
• Data encoded with sealed trait/case
classes
• Patterns at the function level with
typeclasses using parametric functions