meet scala
Post on 15-Apr-2017
189 Views
Preview:
TRANSCRIPT
Meet scala
Wojciech PitułaFor AMG.net
Agenda
What is it?
Old features done better
New features
Why scala?
What is it?
JVM language
Object-functional
Scripting
Java compatible
CONCISE
Old features done better
Syntax
Classes and Objects
Basic Types and Operations
Built-in Control Structures(if, while, switch)
Packages and Imports
Assertions and Unit Testing
Collections
Type Parameterization(Generics)
Syntax
def max(ints: List[Int]): Int = {
def max(x:Int, y:Int) : Int = if(x>y) x else y
ints.fold(Int.MinValue)(max(_,_))
}
val maxVar = max(List(1,2,3,4))
vals and vars
name: Type[typeParam]
def method(param1:pType, param2:pType): mType = { … }
array(2) instead of array[2]
not mandatory semicolon(;)
operators
Alternative method call “object method arg”
Type inference
Named parameters
Integer max(List<Integer> ints){
Integer max = Integer.MIN_VALUE;
for(Integer intEl : ints)
if(intEl > max)
max = intEl;
return max;
}
Classes and Objects
Singleton companion objects
Default constructor
Mandatory override modifier
One namespace for fields and methods
class Rational(n: Int, d: Int) {
require(d != 0)
private val g = gcd(n.abs, d.abs)
val numer = n / g
val denom = d / g
def this(n: Int) = this(n, 1)
def + (that: Rational): Rational =
new Rational(
numer * that.denom + that.numer * denom,
denom * that.denom
)
def * (that: Rational): Rational = new Rational(numer * that.numer, denom * that.denom)
override def toString = numer +"/"+ denom
private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b)
}
Evaluated at construction time
Default public modifier
No get/set convention
Complicated access modifiers
you don’t want to know about
Basic Types and Operations
All the Java literals
(”””str”””) raw, multiline string(escapes doesn’t work)
Operators are methods, (1).+(2)
Object equality checked by ==, !=, not by .equals()
Reference equality checked by eq() method
foo(bar) is equal to foo.apply(bar)
Rich primitive types by implicit conversion
Any, AnyRef, Nothing
Built-in Control Structures(if, while, switch)
They return values!
Complicated for expression
Producing collections with for and yield
Catch with pattern matching
match – switch on steroids
No break and continue
println(if (!args.isEmpty) args(0) else "default.txt")
def grep(pattern: String) =
for (
file <- filesHere
if file.getName.endsWith(".scala");
line <- fileLines(file)
if line.trim.matches(pattern)
) yield (file +": "+ line.trim)
try {
val f = new FileReader("input.txt")
// Use and close file
} catch {
case ex: FileNotFoundException => // Handle missing file
case ex: IOException => // Handle other I/O error
}
def describe(x: Any) = x match {
case 5 => "five"
case true => "truth"
case "hello" => "hi!"
case Nil => "the empty list"
case _ => "something else"
}
Packages and Imports
Java-like or C#-like packages
Imports can be declared anywhere
And are much more powerful
package bobsrockets {
package navigation {
// In package bobsrockets.navigation
class Navigator
package tests {
// In package bobsrockets.navigation.tests
class NavigatorSuite
}
}
}
// easy access to Fruit
import bobsdelights.Fruit
// easy access to all members of bobsdelights
import bobsdelights._
// easy access to all members of Fruits
import bobsdelights.Fruits._
//import only Apple and Orange
import Fruits.{Apple, Orange}
//import all Fruits but Orange and rename Apple to McIntosh
import Fruits.{Apple => McIntosh, Orange =>_, _}
Assertions and Unit Testing
Static assert() and non-static ensuring()
JUnit, TestNG, ScalaTest, specs
import org.specs._
import Element.elem
object ElementSpecification extends Specification {
"A UniformElement" should {
"have a width equal to the passed value" in {
elem('x', 2, 3).width must be_==(2)
}
"have a height equal to the passed value" in {
elem('x', 2, 3).height must be_==(3)
}
"throw an IAE if passed a negative width" in {
elem('x', -2, 3) must throwA[IllegalArgumentException]
}
}
}
Collections
Defaults are immutable!
Tuples
Sequences(Arrays, Lists, ArrayBuffers, ListBuffers)
map, flatMap, filter, collect, fold, …
Set, Map, MutableSet, MutableMap
val tuple = (1, “hello”, 3.1)
val (integer, str, dbl) = tuple
Array(1.0, 2.0, 3.0)
List(1, 2, 3, 4)
Set(‘a’, ‘b’, ‘c’)
Map("hi" -> 2, "there" -> 5)
Type Parameterization(Generics)
Types and type parameters are guessed if possible(target typing)
No raw types
Generic types have by default nonvariant (or, “rigid”) subtyping
Lower and upper bounds
scala> val q = Queue(1, 2, 3)
q: Queue[Int] = Queue(1, 2, 3)def doesNotCompile(q: Queue) {}
//variance
trait Q[T] {…} // nonvariant, Q[String] is not instance of Q[AnyRef]
trait Q[+T] {…} // covariant, Q[String] is instance of Q[AnyRef]
trait Q[-T] {…} // contravariant, Q[AnyRef] is instance of Q[String]
class Queue[+T] (private val leading: List[T], private val trailing: List[T] ) {
def enqueue[U >: T](x: U) = new Queue[U](leading, x :: trailing) // ...
}
def orderedMergeSort[T <: Ordered[T]](xs: List[T]): List[T] = {…}
New features
Scripting
Functional/immutable objects
Functions and Closures
Traits
Case Classes, Pattern Matching and Extractors
Implicit Conversions and Parameters
Working with XML
Actors and Concurrency
Scripting
Scala console
Script files
Good debug/testing tool
#!/bin/sh
exec scala "$0" "$@"
!#
// Say hello to the first argument
println("Hello, "+ args(0) +"!")
$ scala
Welcome to Scala version 2.8.1.
Type in expressions to have them evaluated.
Type :help for more information.
scala> 1 + 2
res0: Int = 3
scala> res0 * 3
res1: Int = 9
Functional/immutable objects
Matter of convention
No mutable state(vals of immutable types only)
“Mutating” methods return new object
Mutable alternatives(builders)
+ Easier to reason about
+ Pass freely around the system
+ Thread safe
+ Safe hash keys
- COPY
Functions and Closures
Methods
Nested/local functions
Function literals and values(first-class and higher-class)
Placeholder syntax
Closures
Repeated parameters
Named arguments
Default values
Tail recursion – no stack overflow and overhead
scala> var increase = (x: Int) => x + 1
increase: (Int) => Int = <function1>
scala> increase(10)
res0: Int = 11
val someNumbers = List(11, 10, 5, 0, 5, 10)
someNumbers.foreach((x: Int) => println(x))
someNumbers.filter(x => x > 0)
someNumbers.map(_ * 2)
val f = (_: Int) + (_: Int) ; f(5, 10)
def sum(a: Int, b: Int, c: Int) = a + b + c
val a = sum _ //partially applied function
// also correct: val a = sum
val b = sum(1, _: Int, 3)
def makeIncreaser(more: Int) = (x: Int) => x + more //closure
val inc1 = makeIncreaser(1) // inc1(10) = 11
val inc9999 = makeIncreaser(9999) //inc9999(-9) = 9990
def approximate(guess: Double): Double =
if (isGoodEnough(guess)) guess
else approximate(improve(guess)) // last call in body is recursive
def div(x :Int, y :Int=1) { x*y }
div( y=2 , x=3)
div(3)
scala> var increase = (x: Int) => x + 1
increase: (Int) => Int = <function1>
scala> increase(10)
res0: Int = 11
scala> var increase = (x: Int) => x + 1
increase: (Int) => Int = <function1>
scala> increase(10)
res0: Int = 11
scala> var increase = (x: Int) => x + 1
increase: (Int) => Int = <function1>
scala> increase(10)
res0: Int = 11
scala> var increase = (x: Int) => x + 1
increase: (Int) => Int = <function1>
scala> increase(10)
res0: Int = 11
Traits
Interfaces on steroids
Multiple inheritance
Linear order
Order of mixins is important!
abstract class IntQueue {
def get(): Int
def put(x: Int)
}
class BasicIntQueue extends IntQueue {
private val buf = new ArrayBuffer[Int]
def get() = buf.remove(0)
def put(x: Int) { buf += x }
}
trait Doubling extends IntQueue {
abstract override def put(x: Int) { super.put(2 * x) }
}
trait Incrementing extends IntQueue {
abstract override def put(x: Int) { super.put(x + 1) }
}
trait Filtering extends IntQueue {
abstract override def put(x: Int) {
if (x >= 0) super.put(x)
}
}
val queue = (new BasicIntQueue with Incrementing with Filtering)
• If the behavior will not be reused, then make it a concrete class• If it might be reused in multiple, unrelated classes, make it a trait. • If you want to inherit from it in Java code, use an abstract class.• If you plan to distribute it in compiled form … its more complicated• If efficiency is very important, lean towards using a class.• If you still do not know, start with a trait.
Case Classes, Pattern Matching and Extractorsabstract class Expr
case class Var(name: String) extends Expr
case class Number(num: Double) extends Expr
case class UnOp(operator: String, arg: Expr) extends Expr
case class BinOp(operator: String, left: Expr, right: Expr) extends Expr
A bit like enums
Automatically added factory method,
toString, hashCode, equals, copy
Deep matches
Sealed classes
Subclasses in the same file
Matching coverage check
Extractors – allows you to treat class like a case class
def simplifyAll(expr: Expr): Expr = expr match {
case UnOp("", UnOp("", e)) => simplifyAll(e) // ‘’is its own inverse
case BinOp("+", e, Number(0)) => simplifyAll(e) // ‘0’ is a neutral element for ‘+’
case BinOp("*", e, Number(1)) => simplifyAll(e) // ‘1’ is a neutral element for ‘*’
case UnOp(op, e) => UnOp(op, simplifyAll(e))
case BinOp(op, l, r) => BinOp(op, simplifyAll(l), simplifyAll(r))
case _ => expr
}
def describe(x: Any) = x match {
case 5 => "five"
case true => "truth"
case "hello" => "hi!"
case Nil => "the empty list"
case _ => "something else"
}
object EMail {
// The injection method (optional)
def apply(user: String, domain: String) = user +"@"+ domain
// The extraction method (mandatory)
def unapply(str: String): Option[(String, String)] = {
val parts = str split "@"
if (parts.length == 2) Some(parts(0), parts(1)) else None
}
}
Implicit Conversions and Parameters
Implicit conversion
Only definitions marked implicit are available
An inserted implicit conversion must be in scope as a single identifier, or
be associated with the source or target type of the conversion.
One-at-a-time Rule: Only one implicit is tried
Whenever code type checks as it is written, no implicits are attempted.
Implicit parameters
implicit def function2ActionListener(f: ActionEvent => Unit) =
new ActionListener {
def actionPerformed(event: ActionEvent) = f(event)
}
class PreferredPrompt(val preference: String)
object Greeter {
def greet(name: String)(implicit prompt: PreferredPrompt) {
println("Welcome, "+ name +". The system is ready.")
println(prompt.preference)
}
}
object JoesPrefs {
implicit val prompt = new PreferredPrompt("Yes, master> ")
}
import JoesPrefs._
Greeter.greet("Joe")
Working with XML
XML literals
Compiled Xpath-like syntax
Pattern matching
scala> val yearMade = 1955
scala> <a> { if (yearMade < 2000) <old>{yearMade+”r.”}</old>
else xml.NodeSeq.Empty }
</a>
scala> <a><b><c>hello</c></b></a> \ "b"
res10: scala.xml.NodeSeq = <b><c>hello</c></b>
scala> <a><b><c d="world">hello</c></b></a> \\
"c" \ "@d"
res12: scala.xml.NodeSeq = world
abstract class CCTherm {
...
def toXML =
<cctherm>
<description>{description}</description>
<yearMade>{yearMade}</yearMade>
<dateObtained>{dateObtained}</dateObtained>
<bookPrice>{bookPrice}</bookPrice>
<purchasePrice>{purchasePrice}</purchasePrice>
<condition>{condition}</condition>
</cctherm>
}
abstract class CCTherm {
...
def fromXML(node: scala.xml.Node): CCTherm =
new CCTherm {
val description = (node \ "description").text
val yearMade = (node \ "yearMade").text.toInt
val dateObtained = (node \ "dateObtained").text
val bookPrice = (node \ "bookPrice").text.toInt
val purchasePrice = (node \ "purchasePrice").text.toInt
val condition = (node \ "condition").text.toInt
}}
Actors and Concurrency
Anti „synchronized” way
Actor – thread + mailbox + actions
Good style:
Actors should not block
Communicate only via messages
Prefer immutable messages
Akka
Typesafe actors comming
object NameResolver extends Actor {
import java.net.{InetAddress, UnknownHostException}
def act() {
react {
case (name: String, actor: Actor) =>
actor ! getIp(name)
act()
case "EXIT" =>
println("Name resolver exiting.")
// quit
case msg =>
println("Unhandled message: "+ msg)
act()
}
}
def getIp(name: String): Option[InetAddress] = {
try {
Some(InetAddress.getByName(name))
} catch {
case _:UnknownHostException => None
}
}
}
scala> NameResolver.start()
res0: scala.actors.Actor = NameResolver$@90d6c5
scala> NameResolver ! ("www.scalalang.org", self)
scala> self.receiveWithin(0) { case x => x }
res2: Any = Some(www.scalalang.org/128.178.154.102)
scala> NameResolver ! ("wwwwww.scalalang.org", self)
scala> self.receiveWithin(0) { case x => x }
res4: Any = None
Why scala?
Conciseness
Immutability
Modernity
Convenience
References
Programming in Scala
Free at http://www.artima.com/pins1ed/
Scala for Java Programmers Tutorial
http://docs.scala-lang.org/tutorials/scala-for-java-programmers.html
top related