Scala Intro training @ Lohika, Odessa, UA.
This is a basic Scala Programming Language overview intended to evangelize the language among any-language programmers.
14. You do not need CS degree to code in Scala
Application Programmers:
A1 – A3 levels
Library Designers:
L1 – L3 levels
«One can program very productively in Scala on level A1, which one
should be able to pick up in a day or so, coming from Java.
Mastering A2 will doubtlessly increase programmer productivity.
A3 is for expert programmers with more specialized tasks, not
everyone needs to get to that level.»
http://www.scala-lang.org/old/node/8610.html
16. #1 - Mutability is evil
#2 – Everyhting returns data
#3 – Functions are first-class citizens
17. Mutability is evil
• Mutable objects are complicated to think about
• Defensive copies
• Need to be synchronized in multithreaded env
• Unobvious side effects
18. Mutability is evil
val salary = "2000$"
salary = "2500$" // does not compile
var salary = "2000$”
salary = "2500$” // compiles
19. Everything returns data
val result = if (true) value1 else value2
val result = for (i <- 1 to 10) yield i
def getRandom() = {
Math.random()
}
20. Functions are first-class citizens
Assign function definitions to variables
val doubled = (x:Int) => x * 2
21. in Scala a function value is an object!
Scala => pure OOP & full-blown functional language
25. #1 - Class
#2 - Object = build-in singleton pattern
#3 – Case class
#4 – Abstract class vs Trait
#5 – Multiple inheritance
WAT? Diamond problem solved!
26. Class
Class is similar to any other languages’ class notion
class MyZombie {
private val index: Int = 0
val name: String = "Zombie0"
}
37. #1 - Scala basic types are objects
#2 – Scala implement it’s own types, wraps and extends
some Java classes and types
#3 Scala operators are method calls
38. Value type
Range
Byte
8-bit signed two's complement integer (27 to 27 - 1, inclusive)
Short
16-bit signed two's complement integer
(-215 to 215 - 1, inclusive)
Int
32-bit signed two's complement integer
(-231 to 231 - 1, inclusive)
Long
64-bit signed two's complement integer
(-263 to 263 - 1, inclusive)
Char
16-bit unsigned Unicode character (0 to
216 - 1, inclusive)
String
a sequence of Chars
Float
32-bit IEEE 754 single-precision float
Double
64-bit IEEE 754 double-precision float
Boolean
true or false
51. Functions are first-class citizens
Assign function definitions to variables
val doubled = (x:Int) => x * 2
52. Functions are first-class citizens
Pass function as a parameter
def traverseTree (callback: (Element) => Unit) {
val element = ??? //Getting tree element
callback(element)
}
53. Functions are first-class citizens
Return function as a result value
def prepareCalculator(x: Int, y: Int): () => Int = {
println("calculating...")
() => x + y
}
55. You can omit types in declarations!
The compiler will infer them for you.
Less typing -> less reading -> happier developers
56. Type inference with variables
private val index = 0
val name = "Zombie0"
private val index: Int = 0
val name: String = "Zombie0"
57. Type inference with functions
Scala compiler can not read thoughts
def func (a: Int, b: String) = { a + b } // compiles
def func1 (a, b) = { a + b } // does not compile
58. Type inference
def getZombies(severity: Int) = {
if (severity > 10) {
List()
} else {
List(Zombie("Mig"), Zombie("Alex"))
}
} // inferred type = List[Zombie]
62. Closure is special kind of a function
Closure encloses the local lexical context inside the function body
Closures can be implemented using Anonymous classes in Java
(yuck!)
64. Closure vs Function
Pure function calculates its result solely in terms of its arguments!
Closure can use the outer lexical context for it computations.
One may say that it stores “references” to the outer values.
68. Sugar : Filtering
Java:
List<Integer> numbers = new ArrayList<Integer>(){{
add(1); add(2); add(-55); add(-33); add(122);
}};
List<Integer> negativeNumbers = new ArrayList<Integer>();
for (Integer number : numbers) {
if (number < 0) {
negativeNumbers.add(number);
}
}
Scala:
val numbers = List(1, 2, -55, -33, 122)
val negativeNumbers = numbers.filter(_ < 0)
69. Sugar : Classification
Java:
List<Integer> numbers = new ArrayList<Integer>(){{
add(1); add(2); add(-55); add(-33); add(122);
}};
List<Integer> negativeNumbers = new ArrayList<Integer>();
List<Integer> positiveNumbers = new ArrayList<Integer>();
for (Integer number : numbers) {
if (number < 0) {
negativeNumbers.add(number);
} else {
positiveNumbers.add(number);
}
}
Scala:
val numbers = List(1, 2, -55, -33, 122)
val (positiveNumbers, negativeNumbers) = numbers.span(_ > 0)
70. Stuff : Tuples
• Tuples can be viewed as simple immutable collections.
• Tuple can contain up to 22 elements of different types.
• Very useful when you need to return a complex value from
the expression
71. Stuff : Tuples
val pair = (22, "zombies")
val pair = (22 -> "zombies")
// the type is Tuple2[Int, String]
println(pair._1)
println(pair._2)
72.
73. Mutable vs Immutable
Prefer immutable collections by default. Period.
Google for details.
Scala uses immutable collections by default
val map = Map("one" -> 1)
//results in scala.collection.immutable.Map[String,Int]
74.
75. Collections practices
Map, Set and List are mostly used collections in Scala
Use traits’ companion object calls to create
collections when you do not need specific
implementation:
Map("one" -> 1) // good
HashMap("one" -> 1) // not so good
new HashMap("one" -> 1) // won't compile :)
76. Collections API
example #1
case class User(name: String, password: String)
val users = List("admin:nimda", "user1:asddsa", "root:qwerty")
val mappedUsers = users.map {
user =>
val splitted = user.split(":")
User(splitted(0), splitted(1))
}
// List[User] = List(User(admin,nimda), User(user1,asddsa), User(root,qwerty))
77. Collections API
example #2
val names = List(
"Alex,Viktor,Eugeny",
"Dmitry,Yegor, Sergey",
"Michael,Sergey")
val splitted = names.flatMap(_.split(",").toList).distinct
// List(Alex, Viktor, Eugeny, Dmitry, Yegor, Michael, Sergey)
79. Loops & For comprehension
• Scala has a while loop
• Scala has a do-while loop
• They are not expressions (the return type is Unit)
80. Loops & For comprehension
Because the while loop results in no value, it is often left out of
pure functional languages.
Such languages have expressions, not loops.
Scala includes the while loop nonetheless, because sometimes
an imperative solution can be more readable, especially to
programmers with a predominantly imperative background.
88. For + generator + filter
for (zombie <- zombieHorde if zombie.isMoving)
kill(zombie)
89. For + generator + filter + yield
This will produce a new collection!
val killedZombies =
for (zombie <- zombieHorde if !zombie.isMoving)
yield zombie
92. Simple matching
val status: String = "R”
val translated = status match {
case "R" => "running”
case "D" => "digesting”
case "E" => "eating brainz”
case _ => "X3"
}
93. Structure matching
case class User(name: String, lastname: String, age: Int)
val users = List(
User("Alexey", "Migutsky", 25),
User("Alexander", "Albul", 27),
User("John", "Doe", 99)
)
val determined = users.map {
case User("Alexey", _, _) => "L”
case User("Alexander", _, _) => "A”
case _ => "X3"
}.mkString(",")
// L,A,X3
94. Structure matching
def describe(list: List[Int]) {
list match {
case first :: second :: third :: tail => println("First case")
case head :: tail => println("Second case")
case Nil => println("Empty list")
}
}
describe(List(1,2,3)) // First case
describe(List(1, 2)) // Second case
describe(List()) // Empty list
97. Implicits
The compiler can insert parameters and call conversion methods
automatically based on the types used
This behavior can be achieved using the implicit modifier
98. #1 - Implicit parameters
#2 – Implicit type conversion
#3 – “Pimp my Library”
99. Implicit parameters
case class Context(data: List[String])
implicit val context = Context(List("a", "b", "c"))
object SomeService {
def printCtx(implicit ctx: Context) =
println(ctx.data.mkString(","))
}
SomeService.printCtx
// a,b,c
100. Implicit type conversion
Compiler will use the implicit conversion method automatically!
case class User(first: String, last: String)
def printUserInfo(user: User) {
println("User name is: " + user.first
+ ", last name is: " + user.last)
}
implicit def stringToUser(userString: String): User = {
val split = userString.split(" ")
User(split(0), split(1))
}
printUserInfo("Alexander Albul")
101. Pimp My Library
case class User(first: String, last: String)
implicit class ExtendedString(str: String) {
def toUser: User = {
val split = str.split(" ")
User(split(0), split(1))
}
}
def printUserInfo(user: User) {
println("User name is: " + user.first +
", last name is: " + user.last)
}
printUserInfo("Alexander Albul".toUser)
106. Stuff : Object equality
The equality operator == do the following
1. Check the left side for null
2. If left side is not null, then call equals method
Scala provides a facility for comparing reference equality, as
well, under the name eq. However, eq and its opposite, ne,
only apply to objects that directly map to Java objects.
107. Stuff : Packages and Imports
• Scala code resides in the Java platform’s global
hierarchy of packages.
• Package definition is at the top of the file.
• The structure is reflected on file system.
package graveyard
class Zombie
108. Stuff : Packages and Imports
• The other way you can place code into packages in Scala is
more like C# namespaces (called packaging)
• Packages can be nested
package graveyard {
package gravestone {
class Zombie
}
}
109. Stuff : Packages and Imports
In Scala, packages and their members can be imported using
import clauses. Imported items can then be accessed by a simple
name like Zombie , as opposed to requiring a qualified name like
graveyard.gravestone.Zombie.
// import Zombie
import graveyard.gravestone.Zombie
// import all undead horde
import graveyard._
110. Stuff : Packages and Imports
• Imports may appear anywhere
• Import may refer to objects (singleton or regular) in addition to packages
• Import let you rename and hide some of the imported members
// please don't do this IRL: aliases must be reasonable!
import graveyard.gravestone.{Zombie => RoseBush}
def hideUndead(): RoseBush = {
import graveyard.gravestone.{Zombie => OldMan}
new OldMan()
}
111. Stuff : Identifiers
1. CamelCase
2. Alphanumeric for variables – letters + digits
3. Do not use starting $ - it is reserved for compiler variables
4. Do not use _ in names – underscore has other usages
5. Constants has first uppercase letter – math.Pi
112. Stuff : Method call
Method with 0 parameter can be called without ()
Method with 1 parameter can be called using infix notation
new Test().method
// method call
new Test().function // res1: () => Unit = <function0>
new Test() method1 10 // 13
113. Stuff : Method call
Use higher-order functions with infix notation, but not with mixed notation
List("abcd","zyxwvu").map (_.toUpperCase).filter (_.length > 5) // bad!
List("abcd","zyxwvu") map (_.toUpperCase) filter (_.length > 5) // good
114. Stuff : Method calls
Use infix notation only with methods without side effects
(which do not modify internal class state)
List(1,2) mkString "" // ok
new CustomDataset() add "some value" // not ok
115. Lazy evaluation
An expression that has a value, but that is not
evaluated until it's actually needed (in another words
– until the value is actually read).
116. Call by-name parameter
Lazy evaluated parameter
def callByValue(x: Int) = {
//parameter get evaluated upon function call
println("x1=" + x)
println("x2=" + x)
}
def callByName(x: => Int) = {
println("x1=" + x) // parameter get evaluated here
println("x2=" + x) // parameter get evaluated again
}
117. Lazy initialization
When a val is declared with the lazy modifier the righthand side of the value (the definition) will not be
executed until the first time the value is accessed.
val normal = 5 // evaluated immediately
lazy val lzy = 5 // evaluated only upon first read
118. Stuff : Streams
A stream is like a list except that its elements are
computed lazily. Because of this, a stream can be
infinitely long.
Only those elements requested will be computed.
Otherwise, streams have the same performance
characteristics as lists.
119. Stuff : Streams
Classical example: Fibonacci sequence
def fibFrom(a: Int, b: Int): Stream[Int] = {
a #:: fibFrom(b, a + b)
}
120. Tail recursion
Scala compiler can transform a recursive call into a
loop so that it won’t use stack for evaluation!
But it can apply its magic only in case of tail
recursion.
121. Tail recursion
Tail recursion is simple:
If the last evaluated expression in a function only
makes a recursive call, but does not make
additional computations, than the function is tail
recursive!
122. Tail recursion : example
def boom(x: Int): Int =
if (x == 0) throw new Exception("boom!")
else boom(x - 1) + 1
@tailrec
def bang(x: Int): Int =
if (x == 0) throw new Exception("bang!")
else bang(x - 1)
125. Monad
Monad is a name of abstraction.
1.
2.
3.
4.
Chain function calls
“Container” type
Composable with each other
Wrap types, which are stored in the monad, into a
monad type (like zombies – their bites turn
everyone in a zombie)
126. Monad
You may have been working with monads already!
• Promises are monads!
• jQuery object is a monad!
• Futures (partial monadic API)
127. Monad
Every monad can:
• Wrap a value into a Monad type
• Unwrap a value from a Monad type
• Work transparently with wrapped value using
Monad interface
128. Monads like Zombies
Every good zombie can:
• Turn a person into a zombie
• Turn back into a person if cured
• Communicate with other zombies as if those were
people
129. Monads
Monad is a really tough topic for beginners!
Spend at least a week cranking the theory to create
you own vision of this abstraction!
130. Option
Scala has a standard type named Option for optional
values.
One can say, that Option is a replacement for Nullobject pattern.
It eliminates the null-checks in the code!
It eliminates Null-Pointer Exceptions!
131. Option
Option have two forms:
• Some(x)
• None
Scala collections do not return nulls,
they return None!
132. Option
The most common way to take optional values apart is
through a pattern match.
def show(x: Option[String]) = x match {
case Some(s) => println(s)
case None => println("?")
}
133. Option
Option is a collection!
Well, it is actually a single-value container
You can use map, filter, flallen, for-comprehension and
other collection API methods with Option!
http://danielwestheide.com/blog/2012/12/19/the-neophytes-guide-to-scala-part-5-the-option-type.html
http://blog.tmorris.net/scalaoption-cheat-sheet/
134. Option : Practices
• You should avoid null as much as possible in Scala
• Use Option when you can return something like a “no
value”
• Do not use null-checks in scala, use collection
API/pattern matching over Option
135. Try
A monad for exception handling.
Its main purpose is to wrap the exception and pass it
around the code (e.g. to another execution context)
Was developed by Twitter team to pass exceptions
across cluster nodes.
138. Try : Practices
• Use Try rather than a catch block for handling
unexpected failure.
• Use Try when working with Future.
• Exposing Try in a public API has a similiar effect as a
checked exception. Consider using exceptions
instead.
142. Resources
• Scala Twitter School [link]
• Effective Scala [link]
• Scala for Java Programmers [link]
• The Neophyte’s Guide to Scala [link] [book]
• Functional Programming Principles in Scala @ Coursera [link]
• Programming in Scala [book]
• ScalaUA skype chat [link]
Editor's Notes
Step 1 – 10 mins1. Scala history2. Complexity3. Use cases4. Who is using5. Use Java libs6. Multiparadigm language7. Prefer functional style8. Expressiveness9. Strongly statical typed10. Hello World
Design started in 2001First release – 2003Author - Martin Odersky1000 downloads/month on official site today
NB: the actions uponBigInt seems like actions over the built-in language features (types)* Scalable language – can be “scaled” by developer’s needs.* It suits great to write DSLs.
Step 2 – 15 mins1. What is immutability2. Why is it matter3. Difference between val / var (Example showing that we cannot re-asinval)4. Collections are immutable5. Mutable approaches allowed but not prefered6. Everything returns data (example with Java vsScala if statement)
----- Meeting Notes (16.10.13 10:57) -----Add val and var examples
The second main idea of functional programming is that the operations of a program should map input values to output values rather than change data in place. Another way of stating this second idea of functional programming is that methods should not have any side effects.
----- Meeting Notes (16.10.13 14:02) -----Add additional pointsAdd note to slide to see later
Promotes declarative functional style vs imperative style
Immutability => bad performance (memory)Objects everywhere => bad performance NOPE!Scalavsoptimezed C++ = (x2.5 - x3.6)Java vs opt C++ = (x3.7 – x5.8)
Step 3 – 25 mins1. Class = Java Class. Nothing special. Example. How constructor works.2. Object = singleton pattern (Example)3. Case class = class with convenient extensions (POJO in other words) (Example)4. Abstract class - do define structure5. Trait - to define behaviour. Stack modifications.6. Diamond problem solved
----- Meeting Notes (16.10.13 10:57) -----Fiz >> to "
Companion object pattern ?
What does “case” mean?Getters/setters + constructor + apply/unapply (pattern matching) + companion object
What does “case” mean?Getters/setters + constructor + apply/unapply (pattern matching) + companion object
----- Meeting Notes (16.10.13 11:24) -----Add logger exampleAdd abstract class and trait exampleAdd #5 - Diamond problem solved slide
Step 4 – 10 minutes1. Scala basic types are objects (no primitives) 2. Scala implement own types3. Type list
+ Literals+ Reside in scala package+ Imports automatic
Step 5 – 20mins1. Any is a top of hierarchy2. Basic types extends AnyVal3. Others extends AnyRef4. Any class extends Null implicitly5. Any class extends Nothing. Nothing is used in methods which returnds nothing (throw exception of terminate application)6. Unit = void----- Meeting Notes (16.10.13 11:24) -----Add User = null exampleadd Nothing example with throwLocalozedException
Step 6 – 25 mins----- Meeting Notes (16.10.13 14:02) -----Add first class function example and slides
Note that it is "idealogically"Add right examples
----- Meeting Notes (16.10.13 14:02) -----Add additional pointsAdd note to slide to see later
Step 7 – 15 min1. What is type inference2. Example with assigning variable3. Example with method return type4. Method parameters require types!Yes, it is logical. No, compiler cannot read your mind.
----- Meeting Notes (16.10.13 14:02) -----Remove class wrapper context
----- Meeting Notes (16.10.13 14:02) -----remove b:String - StringAdd Alex's examplesAdd example with if then else with
Lambda syntax
Step 8 – 30 minReplace with:2) Closure (definition, difference from lambda)3) Posible problems4) Closures like anonymous class in Java5) Full example
Step 9 – 60 min1. 2 Different types of collections. Mutable / Immutable. Show package names.2. Class Hierarchy (http://www.programmera.net/scala/img/seq_tree.png)3. 3 main traits (Map, Set, List) examples. (Immutable)Live codding. Show only main methods like map, flatMap, filter, foreach, reduce.Others will be shown in a table with a short description