meet scala

23
Meet scala Wojciech Pituła For AMG.net

Upload: wojciech-pitula

Post on 15-Apr-2017

188 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Meet scala

Meet scala

Wojciech PitułaFor AMG.net

Page 2: Meet scala

Agenda

What is it?

Old features done better

New features

Why scala?

Page 3: Meet scala

What is it?

JVM language

Object-functional

Scripting

Java compatible

CONCISE

Page 4: Meet scala

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)

Page 5: Meet scala

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;

}

Page 6: Meet scala

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

Page 7: Meet scala

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

Page 8: Meet scala

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"

}

Page 9: Meet scala

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 =>_, _}

Page 10: Meet scala

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]

}

}

}

Page 11: Meet scala

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)

Page 12: Meet scala

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] = {…}

Page 13: Meet scala

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

Page 14: Meet scala

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

Page 15: Meet scala

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

Page 16: Meet scala

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

Page 17: Meet scala

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.

Page 18: Meet scala

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

}

}

Page 19: Meet scala

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")

Page 20: Meet scala

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

}}

Page 21: Meet scala

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

Page 22: Meet scala

Why scala?

Conciseness

Immutability

Modernity

Convenience

Page 23: Meet scala

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