Functional programming avoids changing-state and mutable data. Referential transparency means expressions can be replaced without affecting observable behavior. Pure functions only depend on argument values and have no other effects. Case classes provide functionality like equals, hashCode and pattern matching out of the box. Futures allow running blocking operations asynchronously and chaining results with map, flatMap and for comprehensions. Implicits allow type conversions and providing parameters implicitly. Sealed classes allow exhaustive pattern matching of a type hierarchy.
2. Functional programming
Is a programming paradigm—a style of building the structure and elements of computer
programs—that treats computation as the evaluation of mathematical functions and avoids
changing-state and mutable data.
3. Referential transparency and purity
An expression e is referentially transparent if for all programs p, all occurrences of e in p
can be replaced by the result of evaluating e, without affecting the observable behavior
of p. A function f is pure if the expression f(x) is referentially transparent for all
referentially transparent x.
4. Example of pure function:
def fun(a: Int, b: Int): Int = a / b
5. Example of pure function:
def wrong(a: Int, b: Int): Int = a / b
def right(a: Int, b: Int): Try[Int] = Try(a / b)
11. object UserType extends Enumeration {
type UserType = Value
val NewUser, RecurringUser = Value
}
12. class vs case class
Hashcode
Equals,
Appy
Public access modifiers
Unapply
Immutability
Serializable
copy
13. case classes
case class User(name: String, birthDay: java.util.Date, country: String)
val ivan = User("Ivan", new java.util.Date(), "Thailand")
val pipat = ivan.copy(name = "Pipat")
println(ivan.name)
14. case classes unapply
def getUser(): User = ???
getUser match {
case User("Ivan", _, _) | User(_, _, "Thailand") => action1
case _ => action2
}
16. real cost
case class Person(name: String, lastName: String)
https://pastebin.com/WFbbnZ0Y
https://pastebin.com/20DVQ9QS
17. default values
def findUser(userName: String, birthday: Date = new Date(), country: String =
"Thailand"): User = ???
findUser("name")
findUser("name", country = "USA")
18. unapply
class Hotel(val name: String, val address: String, val country: String)
def getHotel(): Hotel = ???
getHotel() match {
case Hotel(_, "", "UK") => action1
case _ => action2
}
28. Option
val value: String = ???
Option(value).map(someValue => {
val tmp = someValue + 1
println(tmp)
})
29. Option
val value: String = ???
Option(value).map { someValue =>
val tmp = someValue + 1
println(tmp)
}
30. Option
case class User(age: Int, name: String, gender: Option[String])
val user = User(25, "Ivan", Some("male"))
user.gender match {
case Some(gender) => println("Gender: " + gender)
case None => println("Gender: not specified")
}
31. Option
def foo(gender: String): Unit = ???
val user = User(25, "Ivan", Some("male"))
if(user.gender.isDefined) {
foo(user.gender.get)
}
56. Future.sequence
case class User(id: Long)
def getAllUserIds(): List[Long] = ???
def findUserById(id: Long): Future[User] = ???
val usersF: List[Future[User]] = getAllUserIds().map(findUserById)
val allUsersFetchedF: Future[List[User]] = Future.sequence(usersF)
57. for comprehension
val aOption = Some(5); val bOption = Some(6)
aOption.flatMap(a => bOption.map(b => a + b))
for {
a <- aOption
b <- bOption
} yield a + b
58. for comprehension and futures
for {
cityId <- someCalculation()
countryId <- someOtherCalculation()
district <- someDifferentCalculation()
} yield doSomethingWith(cityId, countryId, district)
59. val cityIdF = someCalculation()
val countryIdF = someOtherCalculation()
val districtF = someDifferentCalculation()
for {
cityId <- cityIdF
countryId <- countryIdF
district <- districtF
} yield doSomethingWith(cityId, countryId, district)
60. Implicits conversion
case class User(name: String, age: Int)
implicit def userToString(user: User): String = s"${user.name}${user.age}"
def giveMeString(arg: String): Unit = println(arg)
val IamString = User("string", 42)
giveMeString(IamString)
61. Implicit Parameter
case class Minerals(typeOfMineral: String)
implicit val calcium = Minerals("calcium")
def needMoreMinerals(implicit minerals: Minerals): Unit =
println(minerals.typeOfMineral)
needMoreMinerals
62. PIMP my library
implicit class StringPimp(value: String) {
def allStringsAreMine(): String = "I was enslaved"
}
println("Hello".allStringsAreMine())
63. Abstract methods in traits
trait Foo { def foo() }
trait M extends Foo{abstract override def foo() { println("M"); super.foo() } }
class FooImpl1 extends Foo { override def foo() { println("Impl") } }
class FooImpl2 extends FooImpl1 with M
new FooImpl2().foo()
64. Sealed classes
def getMyOption[T](): MyOption[T] =
???
getMyOption() match {
case MyEmpty => action1
case MySome(a) => action1
}
sealed abstract class
MyOption[T]
case object MyEmpty extends
MyOption[Nothing]
case class MySome[T](t: T)
extends MyOption[T]
case class MyAnotherState[T](t: T)
extends MyOption[T]
65. Resources
Scala for the Impatient
https://pavelfatin.com/scala-collections-tips-and-tricks/
http://danielwestheide.com/scala/neophytes.html
Programming in Scala, 3rd Edition