Intro to Functional Programming in Scala

1,104 views
966 views

Published on

An introduction to Functional Programming in Scala
Demo code:
https://github.com/electricmonk/scala-log-analysis-demo

Published in: Software
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,104
On SlideShare
0
From Embeds
0
Number of Embeds
6
Actions
Shares
0
Downloads
21
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide
  • Statically typed – types are checked in compile time verses runtime
    Strongly typed - each variable must have a concrete type
    You get the best of both worlds – lean code like in dynamic languages and compile-time checking of adherence to structure

    Type inference can slow down compilation – use with care

    Structural types – the canonical example is closeable
  • A case class automatically makes its constructor arguments into vals. It also provides automatic equals, hashCode, toString methods and a very useful copy method which makes use of Scala’s named arguments (with defaults) feature.

    We also see that case classes with proper default argument values are essentially test object builders, which saves us tons of code for test setup
  • Intro to Functional Programming in Scala

    1. 1. Scala 101 Beyond Java: JVM FP, July 2014 Shai Yallin, Wix.com audience.filter(_.usesJava).foreach { member => sayHi(member) }
    2. 2. A short overview of Scala’s features • A functional/OO programming language that runs on the JVM • Everything is an object – no primitive types • Functions are first-class members, every function is a value, including what is usually an operator* • Scala is statically-typed and supports type inference * Some of these are synthetic functions
    3. 3. A short overview of Scala’s features • Lambda expressions, closures and currying naturally • Pattern matching • Multiple inheritance through Traits • Comprehensive collections library
    4. 4. Determinism via Immutability Scala encourages everything to be immutable by default: • Variables (vals) • Collections • Value objects (using Case Classes)
    5. 5. Better type safety • Scala is statically and strongly typed; type inference keeps the code lean and mean • Stricter generics (in comparison to Java) provide better compile- time checks • Advanced features include structural types and type aliases
    6. 6. Case Classes Good software engineering makes use of value objects. These need to encapsulate the way they represent their state, to provide information hiding and to be easy to maintain. case class Person( firstName: String, lastName: String, age: Int) val authorOfPascal = Person("Niklaus", "Wirth", 80)
    7. 7. Case classes give us: Factory methods Person("Niklaus", "Wirth", 80) Hashcode authorOfPascal.hashCode == 1423465897 Equals authorOfPascal.equals(authorOfModula) == true Copy val happyBirthday = authorOfPascal.copy(age = 81) Pattern matching Wait for it :-)
    8. 8. Collections Some collection types: • Seq (abstract ordered sequence) • List (linked list) • Set (yeah, it’s a set) • Map (dictionary/hash) A collection can be: • Immutable / Mutable • Synchronous / Parallel
    9. 9. Collections With type inference, trivial to instantiate val numbers = List(1, 2, 3) val numbers2 = 1 :: 2 :: 3 :: Nil val firstNames = Set("john", "mary", "muhammad”) val caloriesPer100gr = Map( "bacon" -> 541, "fries" -> 312, "lettuce" -> 15 )
    10. 10. Collection functions++ ++: +: /: /: :+ :: ::: : addString aggregate andThen apply applyOrElse asInstanceOf canEqual collect collectFirst combinations companion compose contains containsSlice copyToArray copyToBuffer corresponds count diff distinct drop dropRight dropWhile endsWith exists filter filterNot find flatMap flatten fold foldLeft foldRight forall foreach genericBuilder groupBy grouped hasDefiniteSize head headOption indexOf indexOfSlice indexWhere indices init inits intersect isDefinedAt isEmpty isInstanceOf isTraversableAgain iterator last lastIndexOf lastIndexOfSlice lastIndexWhere lastOption length lengthCompare lift map mapConserve max maxBy min minBy mkString nonEmpty orElse padTo par partition patch permutations prefixLength product productArity productElement productIterator productPrefix reduce reduceLeft reduceLeftOption reduceOption reduceRight reduceRightOption repr reverse reverseIterator reverseMap reverse_::: runWith sameElements scan scanLeft scanRight segmentLength seq size slice sliding sortBy sortWith sorted span splitAt startsWith stringPrefix sum tail tails take takeRight takeWhile to toArray toBuffer toIndexedSeq toIterable toIterator toList toMap toSeq toSet toStream toString toTraversable toVector transpose union unzip unzip3 updated view withFilter
    11. 11. Collection functions++ ++: +: /: /: :+ :: ::: : addString aggregate andThen apply applyOrElse asInstanceOf canEqual collect collectFirst combinations companion compose contains containsSlice copyToArray copyToBuffer corresponds count diff distinct drop dropRight dropWhile endsWith exists filter filterNot find flatMap flatten fold foldLeft foldRight forall foreach genericBuilder groupBy grouped hasDefiniteSize head headOption indexOf indexOfSlice indexWhere indices init inits intersect isDefinedAt isEmpty isInstanceOf isTraversableAgain iterator last lastIndexOf lastIndexOfSlice lastIndexWhere lastOption length lengthCompare lift map mapConserve max maxBy min minBy mkString nonEmpty orElse padTo par partition patch permutations prefixLength product productArity productElement productIterator productPrefix reduce reduceLeft reduceLeftOption reduceOption reduceRight reduceRightOption repr reverse reverseIterator reverseMap reverse_::: runWith sameElements scan scanLeft scanRight segmentLength seq size slice sliding sortBy sortWith sorted span splitAt startsWith stringPrefix sum tail tails take takeRight takeWhile to toArray toBuffer toIndexedSeq toIterable toIterator toList toMap toSeq toSet toStream toString toTraversable toVector transpose union unzip unzip3 updated view withFilter
    12. 12. Pattern matching abstract class Gender case object Male extends Gender case object Female extends Gender abstract class MaritalStatus case object Single extends MaritalStatus case object Married extends MaritalStatus case object Divorced extends MaritalStatus case object Widowed extends MaritalStatus case class Person( firstName: String, lastName: String, age: Int, gender: Option[ Gender ], maritalStatus: Option[ MaritalStatus ])
    13. 13. Pattern matching def salutation(p: Person) = (p.gender, p.maritalStatus) match { case (Some(Male ), _ ) => "Mr." case (Some(Female), Some(Single) ) => "Miss" case (Some(Female), None ) => "Ms." case (Some(Female), _ ) => "Mrs." case _ => "Unknown" }
    14. 14. Functions as 1st-class members val people = Set( Person("Niklaus", "Wirth", 80), Person("Anders", "Hejlsberg", 53), Person("Martin", "Odersky", 55), Person("Kenneth", "Thompson", 71)) val toddlers = people.filter(person: Person => person.age <= 3) val minors = people.filter(person => person.age < 18) val seniorCitizens = people.filter(_.age >= 65) val isSenior = { person: Person => person.age >= 65} val alsoSeniorCitizens = people filter isSenior
    15. 15. No nulls Scala urges us to declare a possible return value using the Option[T] monad; an option can be either Some(value) or None, and allows us to assume to it can never be null. We can use collection semantics to consume an Option[T]. case class Person( firstName: Option[String], lastName: Option[String], age: Option[Int]) val completelyUnknown = Person(None, None, None) val anonymousAdult = Person(None, None, Some(25)) val agelessPerson = Person(Some("John”), Some("Doe"), None) def ageOf(p: Person): Int = p.age // Won't compile! def unsafeAgeOf(p: Person): Int = p.age.get // What if age is unknown? def ageOrZero(p: Person): Int = p.age.getOrElse(0)
    16. 16. Multiple Inheritance with Traits Similar (but better than) Java 8’s interfaces with default methods, a Scala class can extend multiple Traits; in case of collision, the right-most trait wins.
    17. 17. Example: Logging import org.slf4j._ class ClassWithLogs { private val log = LoggerFactory.getLogger(this.getClass) def getNormalizedName(person: Person) = { log.info("getNormalizedName called") log.debug("Normalizing " + person) val normalizedName = person.firstName.toUpperCase.trim log.debug("Normalized name is: " + normalizedName) normalizedName } } x1000 classes Eagerly evaluated
    18. 18. Example: Logging trait Logging { private val log = LoggerFactory.getLogger(this.getClass) protected def logInfo(message: => String) = if (log.isInfoEnabled) log.info (message) protected def logDebug(message: => String) = if (log.isDebugEnabled) log.debug(message) protected def logWarn(message: => String) = if (log.isWarnEnabled) log.warn (message) protected def logError(message: => String) = if (log.isErrorEnabled) log.error(message) } By-name parameters (lazily evaluated)
    19. 19. Demo Time!
    20. 20. Questions? shaiy@wix.com http://www.shaiyallin.com @shaiyallin

    ×