This is an introductory SCALA workshop for a JAVA developer. Hence, we're going to explore 'functional' side of the language. SCALA is 50% OOP (Object-Oriented-Programming) and 50% FP (Functional-Programming). Main principles of FP are discussed, such as: tail-recursion, currying, pure-functions, lazy evaluation etc.) along with some examples in code.
We look at the basic keywords and constructs in SCALA.
In the end SCALA tools which are helpful for developers are listed.
4. TIOBE index (march 2018):
Language index
Java 1
C++ 3
JavaScript 8
Swift 12
Go 17
Dart 22
Scala 30
Kotlin 38
Bash 43
5. Companies using SCALA
Company Purpose
Twitter throughout the company, own utils
LinkedIn Scalatra microframework
Airbnb Aerosolve - open source machine learning software
Zalando Entire technology stack
Walmart Canada Backend platform
SoundCloud Finagle (micro services), Scalding and Spark (data
processing)
Google Firebase (parts), Nest
Verizon Quiver (multi-graphs), utils, whole tech. stack
Others: Siemens, Sony Pictures, Imageworks, Duolingo...
6. History of SCALA
- Designed by Martin Odersky (who worked on Java generics in
J2SE 5.0, and Pizza - Java with Generics, function pointers,
case-classes, pattern-matching)
- Released in 2003
- In May Odersky launches Typesafe Inc. (now - Lightbend Inc.)
which provides commercial support for Scala
- Scala is one of the few languages developed in close collaboration
with university society (technically “in the Academia”)
- As of now - Scala 2.12.4, increased performance
- SCALA = Java (OO) + Pizza + functional programming focus
* OO - Object Oriented Language
8. Road to functional programming - SCALA
- Seamless integration of functional programming features into an
otherwise object-oriented language
- “scala” - name comes from the ability to scale along with the
growing complexity of the project
- concurrent - ready for multi-core, micro-service world
10. Kotlin vs SCALA
SCALA Kotlin
Java interoperability Java code from Scala (100%)
Scala code from Java (edge
cases not supported)
bidirectional, 100%
Pattern matching yes, better yes
Design designed in the Academia designed by a leading
software/IDE company
Operator overloading yes, better
+ operator looking functions
yes
Compilation slower faster
Community bigger smaller (still relatively new)
Backward compatibility no yes (up to this point)
11. Kotlin vs SCALA
Scala has the right features, but its most obvious
deficiency is very slow compilation," said Dmitry Jemerov,
JetBrains development lead
12. Kotlin vs SCALA
Kotlin is a Better Java
- excellent tools
- syntactic sugar
- performance
- compatibility
- simple rather than formal
SCALA is more powerful than Java
- designed to do things Java cannot
- pattern matching
- monads
- traits
- full-blown closures
etc.
14. Classes and Objects
class Car {
def startEngine(): Unit = {
engine.invokeIgnition()
}
def openDoor(): Unit = {
}
}
object Car {
def build(color: Color): Car = {
new Car().withColor(color)
}
val RED = Color.fromHex(“#FF0000”)
}
15. Methods
class Car {
val engine = new Engine()
def startEngine(): Unit = {
engine.invokeIgnition();
}
def stopEngine = engine.stop
}
- {} are optional
- ; are optional
- () are optional
- return value is optional
- ‘return’ keyword is optional
- whole class body is a ‘constructor’
(functional domain/everything is a func)
- multiple parameter lists [this will exaplained later]
def multiply(x:Int)(y:Int): Int = x * y
16. Method arguments
add({
val res = 33 + 66
println(res)
res
}, 2)
def multiply (elems: Int*): Int = {
elems.foldLeft( 0)((accum, element) =>
accum * element)
}
17. Multiple classes in a file + inner classes
class Graph {
class Node {
var connectedNodes: List[Node] = Nil
}
}
class Tree
28. Functional programming
- computation as the evaluation of mathematical functions
- avoids mutable data, stateless
- expressions/declarations instead of statements
- originates from λ-calculus (lambda calculus)
- concept of "pure function" - always the same result for a
given set of parameters
- methods should have no "side effects"
- everything is a function
29. Lambda calculus
- mathematical formalism
- invented in 1932 by Alonzo Church
- turing complete - universal model of computation
- untyped and typed variety of the calculus
- making one "abstraction" == "declaring" a function λx.x
- everything is a function
32. Currying in SCALA
def add(x:Int): Int=>Int = (y) => x + y
Add function:
def add(x:Int): Int=>Int = (y) => x + y
Curried function (full syntax):
def add(x:Int)(y:Int):Int = x + y
Curried function (short syntax):
add(6)(5)
val add6 = add(6)
add6(5)
val add6 = add(6)_
add6(5)
33. Currying in SCALA
def calculateMean(businessCustomersBasketVal: Int*)
(homeCustomersBasketVal: Int*): Float
Common usages:
or for error handling:
calculateMean(1,2,7,6,5)(1,2)
def registerCustomer (successAction: User => Unit)
(homeCustomersBasketVal:() => Unit): Float
34. EXERCISE 2
Create a curried func
$> brew install scala
Create a curried function which adds two arguments to each other
35. Tail recursion
- Function contains ONLY A SINGLE
recursive call and it is the last statement
to be executed
- Tail recursion can be replaced
by iteration to remove recursion
from the solution
44. Lists
// Create a Scala List in the Lisp style
val list = 1 :: 2 :: 3 :: Nil
// Create a Scala List in the Java style
val list2 = List(1,2,3)
val list3 = List[Number](1,2,3)
// Create a Scala List with the ‘range’ method
val list4 = List.range(1, 10) // List(1, 2, 3, 4, 5, 6, 7, 8, 9)
val list5 = List.range(0, 10, 2) // List(0, 2, 4, 6, 8)
// Create a Scala List with the List class ‘fill’ method
val x = List.fill(3)("foo") // List(foo, foo, foo)
45. Conversion from Java to SCALA collections
import collection.JavaConverters._
List(1,2,3).asJava // Java List
List(1,2,3).asJavaCollection // Java collection
46. Traits
- like Java 8 interfaces (Java 7 could not have interface implementation)
- abstract classes vs traits
- traits cannot have constructor parameters
47. Traits
class Ball {
def props(): List[String] = List()
override def toString() = "It's a" + props.mkString(" ", ", ", " ") + "ball"
}
trait Red extends Ball {
override def props() = super.props ::: List("red")
}
trait Shiny extends Ball {
override def props() = super.props ::: List("shiny")
}
// hint: traits are called from right to left
// that is Red and then Shiny
val myBall = new Ball with Shiny with Red
println(myBall) // It's a shiny, red ball
48. EXERCISE 3
Trait for pretty print
Create a trait which changes behaviour of List’s toString() method
50. Apply and unapply functions
Apply - when you treat your object like a function, apply is the method
that is called
obj(a, b, c) is equivalent to obj.apply(a, b, c)
- one apply()’s args need to match constructor
object User {
def apply(name: String): User = new User(name)
}
51. Apply and unapply functions
Unapply - is used in Scala's pattern matching mechanism and its most
common use I've seen is in Extractor Objects
object User() {
def unapply(arg: User): Option[( String, String)] = {
Option.apply(("a", "b"))
}
}
52. Case classes
// Has properties id & msg
class Message(p_id:String, p_msg:String) {
val id = p_id
val msg = p_msg
}
// Has properties id & msg
class Message2(val id:String,val msg:String)
// Has properties id & msg
case class Message3(id:String, msg:String)
// Getter and setter methods (java) - getId(), setId() etc.
// Has properties id & msg
class Message4(@BeanProperty val id:String, @BeanProperty val
msg:String)
53. Case classes
// custom constructors
case class Message5(@BeanProperty val id:String,
@BeanProperty val msg:String) {
def this() = this(null, null)
def this(msg:String) = this(null, msg)
}
55. Pattern matching
checking value against a pattern
procedural/functional - result can be returned
val random: Int = Random.nextInt(10)
val numberString = random match {
case 0 => "zero"
case 1 => "one"
case 2 => "two"
case _ => "many"
}
56. Pattern matching on type/case classes
abstract class Notification
case class Email(sender: String, title: String, body: String)
extends Notification
case class SMS(message: String) extends Notification
notification match {
case Email(sender, title, body_) =>
print(s"You got an email from $sender with title: $title")
case SMS(message) =>
print(s"You got an SMS! Message: $message")
}
57. Pattern matching on multiple types
abstract class Notification
case class Email(sender: String, title: String, body: String)
extends Notification
case class SMS(message: String) extends Notification
notification match {
case (Email(sender, title, body_) | SMS(message)) =>
print(s"You got a message” )
}
58. Safe pattern matching
object Foo {
def unapply(x : Int) : Option[String] =
if(x == 0) Some("This value is zero") else None
}
val myInt = 1
myInt match {
case Foo(str) => println(str)
}
59. Safe pattern matching
val myInt = 1
myInt match {
case Foo(str) => println(str)
case _ => println("other: _")
}
results in:
63. Pattern matching
Recently languages are borrowing concepts from newer breed of
functional languages. Type inference and pattern matching I am
guessing goes back to ML. Eventually people will come to expect these
features too. Given that Lisp came out in 1958 and ML in 1973, it seems
to take decades for good ideas to catch on. For those cold decades,
these languages were probably considered heretical or worse “not
serious.”
64. EXERCISE 4
Pattern match emails
From a given messages list (mobile + email), select sucessive email
messages from the same person [i.e. ignoring domain names]
val messageList = List(
Message("tom@gmail.com" ,"Message text 1" ),
Message("7742394590","Message text 2" ),
Message("8326192398","Message text 3" ),
Message("lisa@gmail.com" ,"Message text 4" ),
Message("lisa@yahoo.com" ,"Message text 5" ),
Message("harry@gmail.com" ,"Message text 6" )
)
65. EXERCISE 4
Pattern match emailscase class Message(id:String, msg:String)
object Message{
def apply(id:String, msg:String) = new Message(id,msg)
def unapply(m:Message) :Option[(String,String)] = {
if (m == null) None
else Some(m.id, m.msg)
}
}
object EmailAddress {
def apply(uname: String, dname: String) = uname + "@" + dname
def unapply(str: String): Option[(String, String)] = {
val parts = str split "@"
if (parts.length == 2) Some(parts(0), parts(1)) else None
}
}
66. EXERCISE 4
Pattern match emails
def testMessagePattern (msgList:List[Message]):String = {
msgList match {
case Nil => "Not found"
case Message(EmailAddress(u1,d1),_) :: Message(EmailAddress(u2,d2),_) :: _
if u1 == u2 => u1 + " got two successive emails"
case h::t => testMessagePattern(t)
}
}
67. Pattern matching
By default, pattern matching does not work with regular
classes.
Use case classes or implement:
apply()/unapply() methods
69. Higher order functions
- Functional languages treat functions as first-class values
- Function can be passed as a parameter and returned as a result
- Function type :
type A => B is the type of a function that takes an argument of type
A and returns a result of type B (i.e. lambda/closure)
-
70. Lazy evaluation
- Scala uses strict evaluation by default, but allows lazy evaluation
- Some languages use lazy evaluation as default - Haskell
- Lazy == “non strict”, “deferred execution”
Definition of lazy value:
lazy val x = 2 + 2
71. Lazy evaluation
1 less than 30?
1 more than 20?
25 less than 30?
25 more than 20?
25
40 less than 30?
5 less than 30?
5 more than 20?
23 less than 30?
23 more than 20?
23
// (20, 30)
def lessThan30(i: Int): Boolean = {
println(s"n$i less than 30?" )
i < 30
}
def moreThan20(i: Int): Boolean = {
println(s"$i more than 20?" )
i > 20
}
val a = List(1, 25, 40, 5, 23)
val q0 = a.withFilter(lessThan30)
val q1 = q0.withFilter(moreThan20)
for (r <- q1) println(s"$r")
withFilter() - non strict
72. Lazy evaluation
1 less than 30?
25 less than 30?
40 less than 30?
5 less than 30?
23 less than 30?
1 more than 20?
25 more than 20?
5 more than 20?
23 more than 20?
25
23
// (20, 30)
def lessThan30(i: Int): Boolean = {
println(s"n$i less than 30?" )
i < 30
}
def moreThan20(i: Int): Boolean = {
println(s"$i more than 20?" )
i > 20
}
val a = List(1, 25, 40, 5, 23)
val q0 = a.filter(lessThan30)
val q1 = q0.filter(moreThan20)
for (r <- q1) println(s"$r")
filter() - strict eval
73. Cache using lazy evaluation
- If you don’t use cache - the cost is 0 - value will never get evalueted
- If you use cache one or multiple times, the cost is always 1
- You can make a function lazy by assigning it to a lazy val !
- You can use lazy for network calls etc.
def foo(x: Int => Expensive) = {
lazy val cache = x
/* do lots of stuff with cache */
}
74. Unified type system
- Java makes a sharp distinction between primitive types (e.g. int
and boolean) and reference types (any class).
- In Scala, all types inherit from a top-level class Any, whose
immediate children are AnyVal (value types, such as Int and
Boolean) and AnyRef (reference types, as in Java)
- distinction between primitive types and boxed types (e.g. int vs.
Integer) is not present in Scala
- Scala 2.10 allows for new value types to be defined by the user
76. Value classes
class Foo(val name: String) extends AnyVal {
def print = println(name)
}
Value class
- Scala allows user-defined value classes that extend AnyVal
- Value classes in Scala do not allocate runtime objects
- Performance optimization
- Single, public val parameter that is the underlying runtime
representation
- A value class can define defs, but no vals, vars, or nested traits
classes or objects.
77. Value classes
val foo = new Foo("sample value" )
foo.print
- Now one can use newly defined methods
78. Nullability
- SCALA has no built-in support for null-safe types (Int?, Double? etc.)
- Option[T]
val numberOption = List(1,2,3,4).headOption
if (numberOption.isDefined) {
println(numberOption.get)
}
val number = numberOption.getOrElse(-1)
79. Nullability
- NOT SUPPORTED
val connSocketOption = List(connSocket).headOption
connSocketOption?.removeDevice() // NOT SUPPORTED :(
81. Dependencies definition
- + usual maven/gradle syntax
"com.typesafe" % "config" % "1.3.1"
compile “com.typesafe:config:1.3.1”
- ++ adds scala version to the dependency
"com.typesafe.slick" %% "slick" % “3.2.1”
82. Companion objects
- Accompany classes
- Store constant values
- can access methods and fields that are private in the class/trait
-
class Foo() {
def getVersion = "1.2.1"
object c {
val TAG = "[PROCESSING]"
}
}
class ExtString(var str: String) {
var extraData: String = ""
override def toString: String = str + extraData
}
object ExtString {
def apply(base:String) : ExtString = new ExtString(base)
def apply(base:String, extras: String) : ExtString = {
new ExtString(base)
}
}
83. Infinite data structures
- lazy by default, like Haskell, laziness makes it easy to support
infinite data structures
- Scala is not lazy by default. If it was, we could define Fibonacci as:
fibonacci_sequence = for (i <- 0 to infinity) yield fib(i)
fibonacci_sequence.take(10)
84. Infinite data structures
- odd numbers:
def from(n: Int): Stream[Int] = Stream.cons(n, from(n+1))
lazy val ints = from(0)
lazy val odds = ints.filter(_ % 2 == 1)
odds.take(10).print
85. Type classes
- a type system construct that supports ad hoc polymorphism
object Math {
trait NumberLike[T] {
def plus(x: T, y: T): T
def divide(x: T, y: Int): T
def minus(x: T, y: T): T
}
object NumberLike {
implicit object NumberLikeDouble extends NumberLike[Double] {
def plus(x: Double, y: Double): Double = x + y
def divide(x: Double, y: Int): Double = x / y
def minus(x: Double, y: Double): Double = x - y
}
implicit object NumberLikeInt extends NumberLike[Int] {
def plus(x: Int, y: Int): Int = x + y
def divide(x: Int, y: Int): Int = x / y
def minus(x: Int, y: Int): Int = x - y
}
}
}
More info
87. SCALAZ
Scalaz is a Scala library for functional programming.
It provides purely functional data structures to complement those from
the Scala standard library. It defines a set of foundational type classes
(e.g. Functor, Monad) and corresponding instances for a large number of
data structures.
90. Spark
- Source
- open-source cluster-computing framework. Originally developed at
the University of California
- mainframe computing
- written in SCALA
91. SCALA - AKKA agents
- Implement the REACTIVE MANIFESTO
- Binary/fast communication as default
- Easy to implement
98. Twitter & SCALA
- Scala twitter util
- bunch of idiomatic, small, general purpose tools.
- Time, collections,
- source
99. Links / References
- Scala & Scala JS;
- Oracle developers - Scala course - link
- Twitter Scala School - link
- Scala lang overview - link, Scala cheatsheet - link
- Why SCALA - link - interview with Odersky
- Steps in Scala - link (Loverdo, Christos 2010)
- Lightbend - introduction to Scala course - link
- Beyond Java - link
- Kotlin vs Scala - link, link, link
- Java criticism - link
- Can Java be used for functional programming? - link
- Europython - Lambda functions - link
- Functional programming - link
- Functional programming in JavaScript - link
- Mostly Adequate Guide to functional programming - link
- Programming and Problem Solving Using Scala - link
- Tail recursion in scala - link
100. Links / References
- Alexander Alvina,Funtions are variables too, link
- Kotlin & Funtional programming - link
- Scala basics video - link
- Functional programming principles in Scala - link, link, link, link
- Understanding tail recursion - link, link
- Composing traits LEGO style - link
- List creation in SCALA - link
- SCALA collections overview - link
- apply/unapply function - link
- Scala exercises - link
- Differences between lazy and strict evaluation: link
- Guide to Type classes - link
- Scala from a functional perspective - link
- Scala tour - value classes - link, link
- Scala method scope visibility - link
- Functors in SCALA - link
- Functor & Monad - link
- Functor, applicative, monads - link
101. Additional
- Why SCALA & Kotlin? Is Java 8 a truly functional language?
READ
- Learning SCALAZ - READ