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

The Essence and Fundamentals of Scala

The Essence and Fundamentals of Scala

JUG Thüringen, Erfurt

Scala is one of the most popular alternative languages on the JVM. In this talk, we are going to look at what makes this language so interesting: A strong foundation in functional as well as object-oriented programming, combined with a powerful type system. We'll look at how these principles have shaped the language and how to put them to use in practice.

Daniel Westheide

April 26, 2018
Tweet

More Decks by Daniel Westheide

Other Decks in Programming

Transcript

  1. About me • senior consultant at INNOQ • author of

    “The Neophyte’s Guide to Scala” • co-founder of ScalaBridge Berlin • Twitter: @kaffeecoder • website/blog: http://danielwestheide.com
  2. Agenda • intro • basics • Scala’s object-oriented angle •

    Scala’s functional foundation • a rather powerful type system
  3. Look ma, a value! scala> val screamedGreeting = "HELLO WORLD!!!!"

    screamedGreeting: String = HELLO WORLD!!!!
  4. This looks familiar… scala> val firstBangPos = screamedGreeting.indexOf('!') firstBangPos: Int

    = 11 scala> val bang = screamedGreeting.charAt(firstBangPos) bang: Char = !
  5. Defining functions def triangleArea(a: Int, b: Int, c: Int): Double

    = { val s = (a + b + c) / 2 Math.sqrt(s * (s - a) * (s - b) * (s - c)) }
  6. A simple class class Point(x: Int, y: Int) { require(x

    > 0 && y > 0) println(s"Point created with x: $x and y: $y") def toString: String = s"Point(x: $x, y: $y)" }
  7. Uniform access principle class Point(x: Int, y: Int) { require(x

    > 0 && y > 0) println(s"Point created with x: $x and y: $y") val toString: String = s"Point(x: $x, y: $y)" }
  8. Minimal boilerplate class Point(val x: Int, val y: Int) {

    require(x > 0 && y > 0) println(s"Point created with x: $x and y: $y") def toString: String = s"Point(x: $x, y: $y)" }
  9. Everything is an object val x = 5 + 3

    * 2 val x = 5.+(3.*(2))
  10. Expressions everywhere def pluralize(singular: String, n: Int): String = {

    val text = if (n > 1) singular + "s" else singular n + " " + text }
  11. Higher-order functions type EmailFilter = Email => Boolean def newMailsForUser(mails:

    Seq[Email], f: EmailFilter): Seq[Email] = mails.filter(f) newMailsForUser(myEmails, isLong)
  12. Higher-order functions type EmailFilter = Email => Boolean def newMailsForUser(mails:

    Seq[Email], f: EmailFilter): Seq[Email] = mails.filter(f) newMailsForUser(myEmails, _.body.length >= 100)
  13. Higher-order functions def minimumSize(n: Int): EmailFilter = email => email.body.length

    >= n def maximumSize(n: Int): EmailFilter = _.body.length <= n scala> val isLong = minimumSize(100) isLong: EmailFilter = $$Lambda$1285/789178034@1bee0085
  14. Currying scala> val minimumSize: Int => Email => Boolean =

    size => email => email.body.length >= size minimumSize: Int => (Email => Boolean) = $ $Lambda$1305/559179052@8b670c0 scala> minimumSize(100)(email) res0: Boolean = false scala> val isLong = minimumSize(100) isLong: Email => Boolean = $$Lambda$1308/1940974851@55061418
  15. Function composition scala> val wordCount: Email => Int = _.body.split('

    ').length wordCount: Email => Int = $$Lambda$1392/153337703@938e54a scala> def higherThan(threshold: Int): Int => Boolean = _ > threshold higherThan: (threshold: Int)Int => Boolean scala> val isLong = higherThan(100) compose wordCount isLong: Email => Boolean = scala.Function1$ $Lambda$1395/2035659988@71c1e70f
  16. Function composition scala> val wordCount: Email => Int = _.body.split('

    ').length wordCount: Email => Int = $$Lambda$1392/153337703@938e54a scala> def higherThan(threshold: Int): Int => Boolean = _ > threshold higherThan: (threshold: Int)Int => Boolean scala> val isLong = wordCount andThen higherThan(100) isLong: Email => Boolean = scala.Function1$ $Lambda$1374/1682100030@112f8f8f
  17. Algebraic data types sealed trait TrafficLight case object Red extends

    TrafficLight case object Yellow extends TrafficLight case object Green extends TrafficLight
  18. Algebraic data types def mayDrive(tl: TrafficLight): Boolean = tl match

    { case Green => true case Red | Yellow => false }
  19. Algebraic data types scala> val me = ("Daniel", 37) me:

    (String, Int) = (Daniel,37) scala> val (name, age) = ("Daniel", 37) name: String = Daniel age: Int = 37
  20. Algebraic data types final case class Person(name: String, age: Int)

    def greet(p: Person): String = p match { case Person("Daniel", _) => "You look younger than ever!" case Person(_, age) if age > 30 => "Yo, have you come here to die?" case _ => “Hi!" }
  21. Functional error handling sealed abstract class Option[+A] final case class

    Some[+A](value: A) extends Option[A] case object None extends Option[Nothing]
  22. Functional error handling def greet(name: Option[String]): String = name match

    { case Some(name) => s"Nice to meet you, $name!" case None => "Hello, stranger!" }
  23. Functional error handling final case class Person(name: String, age: Option[Int])

    def find(name: String): Option[Person] = ??? scala> val name = find("Daniel").map(_.name).getOrElse("N/A") displayedName: String = N/A scala> val age = find("Daniel").flatMap(_.age) age: Option[Int] = None
  24. Type safety • cheap value classes • phantom types •

    “there is a Prolog in the type system” • http://danielwestheide.com/blog/2015/06/28/put- your-writes-where-your-master-is-compile-time- restriction-of-slick-effect-types.html
  25. Abstraction def higher[A](x: A, y: A, ordering: Ordering[A]): A =

    if (ordering.gt(x, y)) x else y higher(5, 2, Ordering.Int)
  26. Abstraction def higher[A](x: A, y: A)(ordering: Ordering[A]): A = if

    (ordering.gt(x, y)) x else y higher(5, 2)(Ordering.Int)
  27. Abstraction def higher[A: Ordering](x: A, y: A): A = if

    (implicitly[Ordering[A]].gt(x, y)) x else y higher(5, 2)
  28. Abstraction def sequenceOption[A](as: List[Option[A]]): Option[List[A]] = ??? def sequenceTry[A](as: List[Try[A]]):

    Try[List[A]] = ??? def sequenceFuture[A](as: List[Future[A]]): Future[List[A]] = ???
  29. Abstraction trait Traverse[F[_]] { def sequence[G[_]: Applicative, A](fga: F[G[A]]): G[F[A]]

    } val ageOptions: List[Option[Age]] = List(Some(Age(23)), None) val agesOption: Option[List[Age]] = ageOptions.sequence val responseFutures: List[Future[Response]] = List(svc1(), svc2()) val responsesFuture: Future[List[Response]] = responseFutures.sequence