Upload
kerry-newton
View
216
Download
0
Embed Size (px)
Citation preview
ScalaTechnion – Institute of Technology
Software Design (236700)
Based on slides by: Sagie Davidovich, Assaf Israel
Author: Gal Lalouche - Technion 2015 ©
1
What is Scala?
Scala is a static object-functional language
It supports fully object-oriented code
Classes, methods, inheritance, visibility modifiers,…
It is actually more object-oriented than Java, due to lack of primitives, no static members
It supports fully functional code
Lambdas, Closure, Currying, pattern matching, lazy evaluation, tail recursion,…
Most importantly, it allows the developer to mix and match the two
Currying on methods, inheriting functions, …
Compiles to Java bytecode
So it’s easy to call Java from Scala and vice-versa
Author: Gal Lalouche - Technion 2015 ©
2
A note on the “new” features in Java 8All the new features in Java 8 have been in Scala for years
Higher order functions
optional values
Lambda Expressions
The syntactic sugar of Functional Interfaces can be implemented using implicit
default methods on interfaces are actually weak traits
Streams and easy parallelization
Author: Gal Lalouche - Technion 2015 ©
3
Java:
Scala:
Java vs Scala code
Author: Gal Lalouche - Technion 2015 ©
4
class Person {private final String name;private final int age;public Person(String name, int age) {
this.name = name;this.age = age;
}public String getName() { return name; }public int getAge() { return age; }public boolean canDrink() { return age >= 21; }
public String getFirstName() { return name.split(" ")[0]; }}
class Person (val name: String, val age: Int) { def canDrink = age >= 21 val getFirstName: String = name split " " apply 0}
Java:
Scala:
Case classes
Author: Gal Lalouche - Technion 2015 ©
5
case class Person(id: Long) // includes getters/hash/equals/toString
public class Person { long id; @Override public String toString() { return "Person [id=" + id + "]"; } @Override public int hashCode() { return result = 31 + (id ^ (id >>> 32)); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; return id != other.id; }}
Java vs. Scala, at a glance
Java 8 Has primitives
No operator overloading
Statements and expressions
Has static methods and members
Some type inference
Library collections are mutable
default methods
Basic switch functionality
Basic foreach functionality
No extension methods
Has checked exceptions
Type Erasure (JVM property)
Little to no syntactic sugar
Scala Everything is an object
No concept of "operators", just methods
Everything is an expression
Uses a companion object/Singleton
Stronger type inference
Collections are immutable by default
traits
Powerful pattern matching (a la ML)
Powerful for comprehensions
Can define implicit coercions
Doesn’t have checked exceptions
Can get around type erasure
A lot (too much?) of syntactic sugar
6
Everything is an object
Author: Gal Lalouche - Technion 2015 ©
7
Scala has no primitive types
Int is the type of integers and Double is the type of Double Precision
All classes extends Any (this is called a unified type system)
Nothing extends everything (this is called a bottom type)
1 + 2 is actually syntactic sugar for 1.+(2)
Scala allows you to forgoe the . and parenthesis under certain conditions
This also means that operator overloading is supported implicitly
Simply define a method named + or *, or / or pretty much anything…
For example, XML parsing:
val forecast = weather \ "channel" \\ "item" \ "forecast"
Everything is an expression8
In Scala, all statements are actually expressions
Although some may be of type Unit (Scala’s void)
val x: Int = if (flag) 10 else 20 // no need for ?:val compound = { // doSomeCalculation … $ // last argument is considered the return value}val y: Seq[Int] = for (i <- 0 to 10) yield i // list comprehensions
var z = 0val unit: Unit = (z = 10)
val file = try { readFile() } catch { case _: Exception => readOtherFile()}
Object companion
Author: Gal Lalouche - Technion 2015 ©
9
Scala has no static members / methods
Instead, it uses the Singleton pattern and the object keyword
Wait, isn’t Singleton evil?
Well, usually…
But objects are more powerful than simple static methods, since they can also be passed around, extend classes, etc.
Java Scalaclass Person { String name; static boolean isLegal(String name) { //… }}
class Person(val name: String) {}
object Person { def isLegal(name: String) = //…}
Type inference10
Scala has strong type inference (though not as strong as Haskell/ML)
For variables
For methods
For Lambdas
We can also state the explicit return type to have it enforced by the compiler
var x = 3 // discouraged in Scalaval str = "Hello world!" // str’s reference cannot be changed
def getString = {return "Hello world!"
}
List("1","2","3") map (i => i.toInt())
def getString: String = 4 // won’t compileval getInt: Int = "foobar" // won’t compile
Immutability11
So you want to write immutable code in Java…
We can use the final (val in Scala) modifier, but that only applies to the reference itself
What about the referenced object? It can be mutable!
If we want our classes to be truly immutable we have to work hard
We can use immutable objects, but most of the standard java classes and data structures are mutable
This means we have to resort to defensive copying, which is verbose, slow and error-prone
In Scala, all data structures are immutable (“persistent”) by default
This also gives us free generic covariance (i.e., List[Int] extends List[Any])
Traits12
Scala replaces interfaces with traits
Traits are behavioural units, designed for software reuse
Can be composed to create new traits
An alternative to multiple inheritance (e.g., C++) and mixins (e.g., Ruby)
Difference between Traits, Mixins and Multiple Inheritance
Composed traits are flat, mixins are linear and multiple inheritance is a directed acyclic graph
Traits only have a default constructor
Trait conflicts are solved explicitly by the programmer
Traits – Conflict resolution13
Trait conflicts are resolved explicitly
Conflicts can only arise when there are two implementations with the same signature
Since there are no constructors, and all conflicts are resolved explicitly, the model is much simple than multiple inheritance
trait Hodor { def speak = "Hodor!"}trait Stark { def speak = "Winter is coming"}class StarkHodor extends Hodor with Stark { override def speak = "Hodor is coming!" // we can also use super[Hodor].speak }
Traits vs. default Methods14
Traits can be viewed as more powerful default methods
default methods cannot implement non-default methods
Traits can have state
interface Bar { void bar();}interface Foo { default void bar() {…}}class FooBar implements Foo, Bar { // the method bar is considered in conflict and needs to resolved}
trait Counter { var x = 0}
Traits vs. default Methods (cont.)s15
Trait composition can be used to provide required implementationtrait Bar { def bar // this is a required method}trait Foo { def bar = {…} // this is a provide}class FooBar extends Foo with Bar {
// doesn’t need to implement bar}
Traits vs. default Methods (cont.)16
Traits can be composed in runtime (this actually borrows from mixins, i.e., conflicts are resolved linearly)
Traits can access the implementing class instance.
A trait can require more than just methods from its implementing class; it can also impose lower bounds
This is also used for dependency injection (the “cake pattern”)
trait Dancer { def dance = …}class Cat { …}val dancingCat = new Cat with DancerdancingCat.dance
Pattern matching
Author: Gal Lalouche - Technion 2015 ©
17
Scala has a powerful pattern matching mechanism
Simple switch
Type matching
val y = 10val x = y match { case 3 => … case 4 => … case _ => … //default}
val x = y match { case s: String => … case i: Int => … case d: Double => … case tuple: (Int, String) => …} // no match will throw an exception
Pattern matching – sealed classes
Author: Gal Lalouche - Technion 2015 ©
18
Sealed classes can only be extended in the same source file
This generates a compile error for none-exhaustive search
sealed abstract class LogMessagecase class StringMessage(message:String) extends LogMessagecase class ExceptionMessage(exception:Throwable) extends LogMessagecase class BothMessage(message:String, exception:Throwable) extends LogMessage class Logger { def debug(l:LogMessage) = log(10,l) def info(l:LogMessage) = log(5,l) def error(l:LogMessage) = log(1,l) def log(level:Int, l:LogMessage): Unit = l match { case StringMessage(msg) => println(msg) case ExceptionMessage(exception:Error) => exception.printStackTrace }}
Pattern matching (cont.)
Author: Gal Lalouche - Technion 2015 ©
19
Functional progamming
Regular expressions
Much more…
def contains[T](list: List[T], x: T): Boolean { case Nil => false case e :: xs => if (e == x) true else contains(xs, x)}
val Name = new Regex("""(\w+)\s+(\w+)""")"Gal Lalouche" match { case Name(firstName, lastName) => println(firstName + " " + lastName) case _ => println("No match")}
Thing we don’t have time to cover
Author: Gal Lalouche - Technion 2015 ©
20
We only scratched the surface
Implicit methods
Implicit parameters
For comprehensions
Lazy evaluations
Views (similar to stream, but lazier)
Actors (expressive distributed model)
Much, much more…
If you want to know more…
Author: Gal Lalouche - Technion 2015 ©
21
Suggested Reading:
Programming in Scala (The de-facto guide)
Scala in Depth
See more here: http://www.scala-lang.org/documentation/books.html
Coursera: Functional Programming Principles in Scala (by the language creator)
Principles of Reactive Programming (advanced course, by the language creator and several API designers)
So is Scala perfect?
Author: Gal Lalouche - Technion 2015 ©
22
No language is perfectScala takes the “everything but the kitchen sink” approachThis gives us great powerBut With Great Power, Comes Great Responsibility!
So is Scala perfect? (cont.)
Author: Gal Lalouche - Technion 2015 ©
23
All java code looks pretty much the same There no macros, no extension methods, little to no
syntactic sugar (especially before Java 8) You always know where the method comes from
With the exception of static imports
This makes Java very verbose… …but also very simple to read
“Too much syntactic sugar causes cancer of the semi-colons”
Author: Gal Lalouche - Technion 2015 ©
24
Scala has much built into the language (i.e., not part of a library)
Java‘s map:
Scala’s map:
// sum numbers 1 to 100var sum = 0; for (i <- to 100) sum += i(for (i <- 1 to 100) yield i) sum1.to(100).reduce((x: Int, y: Int) => x.+(y))1.to(100).reduce((x, y) => x + y)1 to 100 reduce (_ + _)
<R> Stream<R> map(Function<? super T,? extends R> mapper)
map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That
“Too much syntactic sugar causes cancer of the semi-colons” (cont.)
Author: Gal Lalouche - Technion 2015 ©
25
It is very easy to create DSLs in ScalaScalatest (a unit-testing framework)
The above code compilesBut what’s going on here? is should a method? is be? what is equal or in?
"A List" should "pop values in last-in-first-out order" in { val $ = new MutableList[Int] $ add 1 $ add 2 $ at 0 should be equal 1 $ at 1 should be equal 2 }
“Too much syntactic sugar causes cancer of the semi-colons” (cont.)
Author: Gal Lalouche - Technion 2015 ©
26
You can define new control structures
You can create Python-like syntax
def unless(b: Boolean)(f: => Unit) { if (!b) f}//… unless(x < 10) { println("x >= 10")}
implicit def richBoolean(b: Boolean) = new { def or(other: Boolean) = b || other def and(other: Boolean) = b && other}if ((b or c) and d) { // …}
“Too much syntactic sugar causes cancer of the semi-colons” (cont.)
Author: Gal Lalouche - Technion 2015 ©
27
ProcessBuilder API
Summary
Author: Gal Lalouche - Technion 2015 ©
28
Scala combines functional and object oriented approaches
It is lightweight and expressive, supports DSL with ease, and fully interoperable with Java
However, when a language let’s you do everything, developers also have to know everything Especially when working in teams
Syntactic sugar is cool when working alone, but can quickly get out of hand