advanced scala

Post on 10-Nov-2014

1.005 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

This presentation was part of a seminar in a masters course. It covers 3 chapters of Martin Odersky's Book "Programming in Scala" (Packages and Imports, Assertions and Unit testing, Case Classes and Pattern Matching).

TRANSCRIPT

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Masterseminar Scala

Fabian Becker

FH Giessen-Friedberg

15. November 2010

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Content

1 Packages & Imports

2 Assertions and Unit Testing

3 Case Classes and Pattern Matching

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Packages

Packages

Important to minimize coupling

Scala code resides in Java global hierarchy of packages

Per default code is in the unnamed package

There are two ways to place code inside packages

Listing 1.1

package database.mysql

class Query

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Packages

Listing 1.2

package database {

package mysql {

class Query

}

}

Listing 1.3

package database.mysql {

class Query

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Packages

Packages

Packages in Scala truly nest

In Java packages are in a hierarchy they don’t nest

Naming a package in Java you always start at the root

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Packages

Listing 1.4: Accessing packages

package game {

package ui {

class Player

}

package engine {

class Main {

// Java: new game.ui.Player()

val player = new ui.Player

}

}

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Packages

Listing 1.5: More complex

package ui { class Player } // In ui.scala

package game { // In game.scala

package ui { class Player }

package engine {

package ui { class Player }

class Main {

val player = new ui.Player

val player2 = new game.ui.Player

val player3 = new _root_.ui.Player

}

}

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Imports

Importing packages

Importing packages allows to directly access members in thatpackage

Scala imports are similar to the imports from Java

Imports can appear anywhere

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Imports

Listing 1.6.1: Defining Enemies

package game

abstract class Enemy(

val name: String,

var lvl: Int

)

object Enemies {

object Dwarf extends Enemy("Gimli", 10)

object Orc extends Enemy("Bwarg", 5)

object Necromancer extends Enemy("Destructor", 99)

val col = List(Dwarf, Orc, Necromancer)

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Imports

Listing 1.6.2: Importing Enemies

// Simple import for Enemy

import game.Enemy

// Import all members of game

import game._

// Import all members of Enemies

import game.Enemies._

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Imports

Listing 1.7: Import in a function

def showEnemy(enemy: Enemy) {

import enemy._

println("Enemy - Name:"+name+" Level:"+lvl)

}

Imports

Imports can appear in functions

They import all members of a object

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Selective Imports

Listing 1.8: Selective Imports

// Only import Dwarf and Orc

import game.Enemies.{Dwarf, Orc}

// Renaming an import

import game.Enemies.{Necromancer => Necro}

// Rename one, import the rest

import game.Enemies.{Orc => O, _}

// Exclude an import

import game.Enemies.{Orc => _, _}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Selective Imports

Selective Imports

Import: import game.Enemies.{Orc} ⇔ game.Enemies.Orc

Rename: 〈originalname〉 ⇒ 〈newname〉Hide Packages: 〈original − name〉 ⇒Catch All: importgame.Enemies.{ } ⇔ game.Enemies.

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Implicit imports

Listing 1.9: Implicit imports

import java.lang._ // everything in the java.lang package

import scala._ // everything in the scala package

import Predef._ // everything in the Predef object

Implicit imports

Packages imported implicitly by Scala

scala. overshadows java.lang.

scala.StringBuilder ⇒ java.lang.StringBuilder

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Access modifiers

Listing 1.10: Private modifiers

class Outer {

class Inner {

private def f() { println("f") }

class MostInner { f(); // OK }

}

(new Inner).f() // fails

}

Private

Scala: private members are only accessible inside the class orobject that contain their definition

Java allows outer classes to access private members of theirinner classes

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Access modifiers

Protected

Java: protected members are accessible within the samepackage

Scala: Only from the object they are defined in and theirsubclasses

Public

There is no explicit modifier for public

All members not labeled private or protected are public

Accessable from anywhere

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Access modifiers

Scope of protection

Scala allows to control access to a level X

private[X] and protected[X] allow access up to X

Listing 1.11: Example

package game {

package ui {

private[game] class Player {

private[this] var hp = 42

protected[ui] def getHP() { hp }

}

}

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Assertions and Unit Testing

Testing Code

Assertions for run-time checking

Unit testing for development testing of small units

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Assertions

Listing 2.1: Assert

def add1(x: Int) : Int = {

val z = x + 1

assert(z > x)

return z

}

println(add1(41))

Assertion methods

Method assert predefined in Predef

assert(condition)

assert(condition, explanations)

If the condition doesn’t hold, an AssertionError is thrown

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Assertions

Listing 1.13: Ensuring

def lvlUp(e: Enemy): Enemy = {

if(e.lvl < 100) {

e.lvl = e.lvl + 1

} ensuring(e.lvl < 100)

e

}

Ensuring

Method assert predefined in Predef

assert(condition)

assert(condition, explanations)

If the condition doesn’t hold, an AssertionError is thrown

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Unit testing

ScalaTest

org.scalatest.Suite (http://www.scalatest.org/)

Can be executed on the Scala console: (newHitchhikerSuite).execute()

Listing 2.3: Simple testcase

import org.scalatest.Suite

class HitchhikerSuite extends Suite {

def testAnswerToLife() {

val answer = 42

assert(answer == 42)

}

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Unit testing

ScalaTest with Fun

ScalaTest allows different styles of testing

FunSuite is a trait that overrides execute and allows to definetests as function values

Naming the tests is easier (you can use Strings)

Listing 2.4: FunSuite

import org.scalatest.FunSuite

class HitchhikerSuite extends FunSuie {

test("The answer to life should be 42") {

val answer = 42

assert(answer == 42)

}

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Unit testing

ScalaTest - Informative testing

A normal assertion produces long error messages but do notshow why the match failed

ScalaTest defines the === operator for assert(), shows thevalues

Alternative: expect(value) { block }

Listing 2.5: Informative testing

assert(answer === 42)

// or

expect(42) {

answer

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Unit testing

ScalaTest - Catching Exceptions

Testing for Exceptions can be done with intercept()

Listing 2.6: Intercept

s = "hi"

intercept[IndexOutOfBoundsException] {

s.charAt(-1)

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Unit testing

JUnit

Most popular test framework for Java

Can easily be used from Scala

Does not natively support Scala’s assertion syntax

Listing 2.7: JUnit Testcase

import junit.framework.TestCase

import junit.framework.Assert.assertEquals

import junit.framework.Assert.fail

class MyTestCase extends TestCase {

def testAnswer() {

val answer = 42

assertEquals(42, answer)

}

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Unit testing

JUnit + Scala

ScalaTest defines JUnit4Suite (requires JUnit 4 of course)

JUnit4Suite extends TestCase

Listing 2.8: Using Scala syntax in JUnit

import org.scalatest.junit.JUnit4Suite

class AnswerSuite extends JUnit4Suite {

def testAnswerToLife() {

var answer = 42

assert(answer === 42)

}

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Unit testing

TestNG

TestNG framework inspired by JUnit/nUnit

Uses annotations

Listing 2.9: TestNG

import org.testng.annotations.Test

import org.testng.Assert.assertEquals

class AnswerTests {

@Test def verifyAnswerToLife() {

val answer = 42

assertEquals(answer, 42)

}

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Unit testing

TestNG + Scala

ScalaTest defines trait TestNGSuite

TestNGWrapperSuite enables TestNG to test Scala while thetests are written in Java

Listing 2.10: TestNG + Scala

import org.scalatest.testng.TestNGSuite

import org.testng.annotations.Test

class AnswerSuite extends TestNGSuite {

@Test def verifyAnswerToLife() {

val answer = 42

expect(42) { answer }

assert(answer === 42)

}

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Unit testing

Listing 2.11: TestNG + Scala

import org.scalatest.Spec

class AnswerSpec extends Spec {

"The Answer" -- {

"should be an integer" - {

val answer = 42

assert(answer.isInstanceOf[Int] == true)

}

"should be 42" - {

val answer = 42

assert(answer === 42)

}

}

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Unit testing

Tests as specification

Behavior-driven-development (BDD) lays emphasis onhuman-readable testing

ScalaTest includes a trait Spec

Spec contains describers and specifiers

Each specifier will be run as a seperate ScalaTest

Output (new AnswerSpec).execute()

The answer- should be an integer- should be 42

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Case Classes and Pattern Matching

Tests as specification

Case Classes

Pattern Matching

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Case classes

Listing 3.1: Definitions

abstract 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

The case modifier

Example from the book

The case modifier adds syntactic conveniences

Factory method: val v = Val(”x”)

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Case classes

Listing 3.2: Nesting

val op = BinOp("+", Number(42), Var("x"))

The case modifier

Allows to ommit the new

All constructor parameters implicitly get a val prefix

toString, equals, hashCode are automagically added

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Pattern matching

Listing 3.3: Matching

def simplifyTop(expr: Expr): Expr = expr match {

case UnOp("-",UnOp("-",e)) => e // Double negation

case BinOp("+", e, Number(0)) => e // Adding zero

case BinOp("*", e, Number(1)) => e // Multiplying by one

case _ => expr

}

Matching

Similar to Javas switch

Syntax: selector match {alternatives}match is an expression and results in a value

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Pattern matching

Patterns

e, variable pattern

, wildcard pattern, drops the value

UnOp(“-“, e), constructor pattern, matches values of typeUnOp with - as first param.

If no pattern matches a MatchError is thrown.

Listing 3.4: Matching

expr match {

case BinOp(_, _, _) => println(expr +"is a binary

operation")

case _ => println("It’s something else")

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Pattern matching

Constant patterns

Any literal (String, Boolean, Integer) can be used as a pattern

Literals match themselves

Listing 3.5: Constant patterns

def inspect(x: Any) = x match {

case 12 => "twelve"

case Nil => "nothing"

case false => "negative"

case _ => "Cant’t say"

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Pattern matching

Variable patterns

Variable pattern matches like a wildcard, but the result getsassigned to the variable

Listing 3.6: Variable patterns

expr match {

case 12 => "Not right"

case number => "This is a number " + number

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Pattern matching

How does Scala tell them apart?

Scala uses a lexical rule to differ between variable andconstant patterns

Lowercase identifiers are treated as variable

Uppercase identifiers are assumed to be a constant

Exception to the rule?

true and false

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Pattern matching

Constructor patterns

Check against a constructor and it’s parameters

Object gets inspected

Contents of the object are checked aswell

Listing 3.7: Constructor pattern

expr match {

case BinOp("-", m, Number(12)) => println(m + " - 12")

case _ =>

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Pattern matching

Sequence patterns

Match against sequence types like List, Array, ...

Allows to specify the number of elements in the pattern

⇔ Wildcard, * ⇔ 0..n elements

Listing 3.8: Sequence pattern with fixed length

expr match {

case List(n, _, _) => println("Top-Element: " + n)

case List(n, _*) => println("Top-Element: " + n)

case _ =>

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Pattern matching

Tuple patterns

A pattern like (x, y) matches a 2-tuple

Listing 3.9: Tuple pattern

expr match {

case (x, y) => println("Matched a 2-tuple")

case _ =>

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Pattern matching

Typed patterns

Alternative for type checks and type casts

Type check: expr.instanceOf[String]

Type cast: expr.asInstanceOf[String]

Listing 3.10: Typed pattern

def getSize(e: Any) = e match {

case s: String => s.length

case m: Map[_,_] => m.size

case _ => -1

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Pattern matching

Type erasure

Matching a Map with special element types doesn’t work!

Scala/Java use the erasure model for generics

No information about type arguments is maintained atrun-time

Arrays are an exception, they are handled differently

Listing 3.11: Type erasure - Matches all Maps!

expr match {

case m: Map[Int, String] => println("String-Int Map")

case _ =>

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Pattern matching

Variable binding

Perform the normal match but bind the match to a variable

The @ sign binds a variable to a match

Listing 3.12: Binding a variable to a match

expr match {

case UnOp("abs", e @ UnOp("abs", _)) => e

case _ =>

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Pattern matching

Pattern guards

Sometimes a match can have pre-conditions

The conditions are “guarding“ the match

Listing 3.13: Match with pre-condition

expr match {

case BinOp("/", _, y) if y == 0 => println("Nominator

can’t be 0")

case _ =>

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Pattern matching

Pattern overlaps

Patterns are tried in the order they’re written

Changing the order of cases can change behaviour

Listing 3.14: Simple pattern overlap

expr match {

case BinOp("+", e, Number(10)) => println("BinOp + 10")

case BinOp("-", e, Number(10)) => println("BinOp - 10")

case BinOp(op, e, Number(10)) => println("BinOp "+op+"

10")

case _ => expr

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Pattern matching

Sealed classes

When you match using patterns, how do you make sure youmatched everything?

sealed classes allow the compiler to know all possible cases

A sealed class can only have subclasses in the same file

The compiler can then generate warnings (match notexhaustive)

Listing 3.15: Sealed class

sealed abstract class Expr

case class Var(name: String) extends Expr

case class Number(num: Double) extends Expr

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Pattern matching

Sealed classes

If you leave out an option a warning is thrown: “warning:match is not exhaustive! missing combination Type“

Listing 3.16: Match on a sealed class

expr match {

case Var(x) => "Variable " + x

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Pattern matching

Sealed classes

Warning can be avoided by doing a wildcard match

Suppressed using an annotation (will be covered in Chapter25)

Usefulness?

Why make the class sealed in the first place?

Listing 3.17: Match on a sealed class

(expr: @unchecked) match {

case Var(_) => "a variable"

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Pattern matching

The Option type

Standard type for optional values

Can be Some(x) or None

Is returned by HashMap, Map, ..

None is the Scala way of returning null

Listing 3.18: Unpacking an option

val map = Map(1 -> "a", 2 -> "b", 3 -> "c")

(map get 1) match {

case Some(s) => println(s)

case None => println("Not there")

}

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Pattern matching

Patterns in other places

Patterns can be used almost anywhere

Listing 3.19: Other uses of patterns

val (a, b) = (1, 2)

for((num, letter) <- Map(1->"a", 2->"b"))

println("Num:"+num+" Letter:"+letter)

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Pattern matching

Case sequences as partial functions

Case sequences can be used partial functions

Partial functions throw a RuntimeException if they are appliedagainst a value they don’t support

Compiler can throw warnings

Listing 3.20: Case sequence as partial function

val myMatch: Option[Int] => String = {

case Some(x) => "Value: " + x

case None => "Nothing there"

}

myMatch(Some(12))

// => Value: 12

Packages & Imports Assertions and Unit Testing Case Classes and Pattern Matching

Pattern matching

Case sequences as partial functions

By telling the compiler that you use a partial function you cancheck whether it’s possible to apply a value

Listing 3.21:

val listMatch: PartialFunction[List[Int], Int] = {

case x :: y :: _ => y

}

// Can we apply the List?

listMatch.isDefinedAt(List(1,2,3))

// => true

top related