learning scala seminar 2fileadmin.cs.lth.se/cs/personal/bjorn_regnell/scala/sem2/sem2.pdf · intro...

Post on 18-Jul-2018

225 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Learning ScalaSeminar 2

2012‐05‐29

Intro

• Last seminar: – overview and background of Scala

• This seminar:– Selected topics from Chapter 1‐12– Presentations and exercises prepared by PhD students aiming for credit points

– Keep time for each presentation within 10 min to leave time for exercises and interactive discussions

Seminar 2 Schedule13:15 INTRO        Björn R. & Christian

13:25 Topic 1. Classes: constructors, auxiliary constructors and access rules        Sardar 13:35 Topic 2. Method overloading, operators and implicit conversion        Niklas13:45 Topic 3. Objects: factory objects and method chaining by returning this    Christian13:55 Topic 4. Inheritance: extending, overriding and final        Jesper14:05 Topic 5. Scala's class hierarchy and Predef        Mehmet14:15 Selected Exercises topics 1‐5        Pairwise exercising

14:30 PAUS

14:45 Topic 6. Built‐in control structures: if, while, for, exceptions        Markus14:55 Topic 7. Tuples, placeholder syntax, closures, tail recursion  Alfred15:05 Topic 8. Control abstraction, currying, and by‐name‐parameters        Björn A. J.15:15 Topic 9. Partially applied functions and special function call forms        Maj15:25 Topic 10. Traits: interfaces, mix‐ins and stackable modifications        Gustav15:35 Selected Exercises topics 6‐10        Pairwise exercising

15:50 OUTRO        Björn R. & Christian

Classes:  Constructors,  Auxiliary  

Constructors  and  Access  Rules  in  Scala    

 By  

Sardar  Muhammad  Sulaman  

•  A  class  is  a  blueprint  for  objects  •  It  defines  characteristics  of  an  object  •  Characteristics  are:  

•    Attributes  (Field  or  Properties)  •    Behaviors  (Methods  or  Operations)  

•  Example:  Car  Class  

Classes  in  Scala  

   Attributes:  •  Year  •  Model  •  Color  •  Engine  etc.  

   

Behaviors:  •  on()  or  off()  •  chngGears()  •  Accelerate()  •  Brake()  etc.  

•  Class  declaration  is  like  Java  •  Instantiation  of  a  class  is  also  same  like  Java  •  In  scala  we  create  variables  either  using  val  or  var    •  Using  val  we  get  a  read  only  variable  (Immutable)  •  Example:  

//Declaration  of  a  class  class  Hello    {  def    greet()  =  println(“Hello  Everyone!”)    }    //Class  instantiation    val  object  =  new  Hello()  object.greet()    

Contd.  

•  They  are  different  than  Java  •  In  Scala  Primary  constructor  is  the  body  of  class,  and  its  parameter  list  comes  after  the  class  name  

•  Example:      //We  will  print  the  hello  message  on  instantiation  

class  Hello(message:  String)    {  Println(“Welcome”)  def    greet()  =  println(message)    }  val  object  =  new  Hello(“Hello  Everyone!”)  object.greet()  //  The  parameter  looks  like  a  field,  but  it  is  not.  The  Compiler  automatically  creates  and  that  is  val  (Immutable)  with  public  access.  

Constructors  

•  Class  body  is  the  Primary  Constructor    •  We  can  add  Auxiliary  Constructors    •  An  auxiliary  constructor  must  call  (on  1st  line  of  its  body)  either  another  auxiliary  constructor  or  the  primary  constructor    

•  They  are  created  by  defining  methods  named  “this”  •  Example:  //  add  another  message  for  aux.  constructor  

class  Hello(message1:  String,  message2:  String)    {  def  this(message:  String)  =  this(message,  “  ”)  //  Calling  primary  cons.  def    greet()  =  println(message1  +  message2)    }  val  object  =  new  Hello(“Hello”)  object.greet()  

Auxiliary  Constructors  

•  Public:  •  Public  is  Scala’s  default  access  level  •  Members  can  be  accessed  from  outside  

•  Private:  •  Private  is  similar  to  Java  •  Member  labeled  private  only  visible  inside  the  class  or  object  

•  It  used  in  inner  classes,  which  is  different  from  Java  

•  Protected:  •  A  bit  more  restrictive  than  Java  •  A  protected  member  is  only  accessible  from  subclass  of  the  class  in  which  the  member  is  defined  (In  Java  it  is  accessible  with  in  a  package)  

Access  Rules  in  Scala  

   

Thanks

Operators,Method overloading and

Implicit conversions

Niklas Fors

May 28, 2012

Introduction to operators

Operators are ordinary methods.

1 + 2

1.+(2)

But they have different precedence and associativity.

Introduction to operators

Operators are ordinary methods.

1 + 2

1.+(2)

But they have different precedence and associativity.

Different types of operators

Prefix operators: +, -, ! and ˜!false ⇒ false.unary !Postfix operators: Arbitrary identifier (e op ⇒ e.op)1 toString ⇒ 1.toStringInfix operators: Arbitrary identifier (e1 op e2 ⇒ e1.op(e2))2.0 + 3.0 ⇒ 2.0.+(3.0)

Infix operators, precedenceRule: Precedence is determined by the first character.

For instance,2 + 3 * 5 ⇒ 2 + (3 * 5)

2 +*** 3 *+++ 5 ⇒ 2 +*** (3 *+++ 5)

2 max 1 + 2 ⇒ 2 max (1 + 2)

i += 3 * 5 ⇒ i += (3 * 5)

(all other special characters)

* / %

+ -

:

= !

< >

&

^

|

(all letters)

(all assignment operators, eg += -= etc.)

Infix operators, precedenceRule: Precedence is determined by the first character.For instance,2 + 3 * 5 ⇒ 2 + (3 * 5)

2 +*** 3 *+++ 5 ⇒ 2 +*** (3 *+++ 5)

2 max 1 + 2 ⇒ 2 max (1 + 2)

i += 3 * 5 ⇒ i += (3 * 5)

(all other special characters)

* / %

+ -

:

= !

< >

&

^

|

(all letters)

(all assignment operators, eg += -= etc.)

Infix operators, precedenceRule: Precedence is determined by the first character.For instance,2 + 3 * 5 ⇒ 2 + (3 * 5)

2 +*** 3 *+++ 5 ⇒ 2 +*** (3 *+++ 5)

2 max 1 + 2 ⇒ 2 max (1 + 2)

i += 3 * 5 ⇒ i += (3 * 5)

(all other special characters)

* / %

+ -

:

= !

< >

&

^

|

(all letters)

(all assignment operators, eg += -= etc.)

Infix operators, precedenceRule: Precedence is determined by the first character.For instance,2 + 3 * 5 ⇒ 2 + (3 * 5)

2 +*** 3 *+++ 5 ⇒ 2 +*** (3 *+++ 5)

2 max 1 + 2 ⇒ 2 max (1 + 2)

i += 3 * 5 ⇒ i += (3 * 5)

(all other special characters)

* / %

+ -

:

= !

< >

&

^

|

(all letters)

(all assignment operators, eg += -= etc.)

Infix operators, precedenceRule: Precedence is determined by the first character.For instance,2 + 3 * 5 ⇒ 2 + (3 * 5)

2 +*** 3 *+++ 5 ⇒ 2 +*** (3 *+++ 5)

2 max 1 + 2 ⇒ 2 max (1 + 2)

i += 3 * 5 ⇒ i += (3 * 5)

(all other special characters)

* / %

+ -

:

= !

< >

&

^

|

(all letters)

(all assignment operators, eg += -= etc.)

Infix operators, associativity

Rule: Associativity is determined by the last character.: is right associative (and is invoked on its right operand!)all other are left associative

For instance,1 + 2 + 3 ⇒(1 + 2) + 3

a ::: b ⇒b.:::(a)

Infix operators, associativity

Rule: Associativity is determined by the last character.: is right associative (and is invoked on its right operand!)all other are left associativeFor instance,1 + 2 + 3 ⇒(1 + 2) + 3

a ::: b ⇒b.:::(a)

Infix operators, associativity

Rule: Associativity is determined by the last character.: is right associative (and is invoked on its right operand!)all other are left associativeFor instance,1 + 2 + 3 ⇒(1 + 2) + 3

a ::: b ⇒b.:::(a)

Method overloading (1/2)

class C {

def m(x: Int): Int = x

def m(x: Int, xs: List[Int]): List[Int] = x :: xs

def m(y: Int): Double = y.toDouble

}

val c = new C()

c.m(1)

c.m(1, List(2,3))

Method overloading (1/2)

class C {

def m(x: Int): Int = x

def m(x: Int, xs: List[Int]): List[Int] = x :: xs

def m(y: Int): Double = y.toDouble

}

val c = new C()

c.m(1)

c.m(1, List(2,3))

Method overloading (1/2)

class C {

def m(x: Int): Int = x

def m(x: Int, xs: List[Int]): List[Int] = x :: xs

def m(y: Int): Double = y.toDouble

}

val c = new C()

c.m(1)

c.m(1, List(2,3))

Method overloading (2/2)

class A

class B extends A

def f(a: A) { println("A") }

def f(b: B) { println("B") }

var r = new A()

f(r)

r = new B()

f(r)

Method overloading (2/2)

class A

class B extends A

def f(a: A) { println("A") }

def f(b: B) { println("B") }

var r = new A()

f(r)

r = new B()

f(r)

Method overloading (2/2)

class A

class B extends A

def f(a: A) { println("A") }

def f(b: B) { println("B") }

var r = new A()

f(r)

r = new B()

f(r)

Operators

class Rational(val n: Int, val d: Int) {

def *(r: Rational)

= new Rational(n * r.n, d * r.d)

def *(i: Int) = new Rational(n * i, d)

}

val r1 = new Rational(1, 2)

val r2 = new Rational(1, 4)

r1 * r2

r1.*(r2)

r1 * 2

2 * r1

Operators

class Rational(val n: Int, val d: Int) {

def *(r: Rational)

= new Rational(n * r.n, d * r.d)

def *(i: Int) = new Rational(n * i, d)

}

val r1 = new Rational(1, 2)

val r2 = new Rational(1, 4)

r1 * r2

r1.*(r2)

r1 * 2

2 * r1

Operators

class Rational(val n: Int, val d: Int) {

def *(r: Rational)

= new Rational(n * r.n, d * r.d)

def *(i: Int) = new Rational(n * i, d)

}

val r1 = new Rational(1, 2)

val r2 = new Rational(1, 4)

r1 * r2

r1.*(r2)

r1 * 2

2 * r1

Operators

class Rational(val n: Int, val d: Int) {

def *(r: Rational)

= new Rational(n * r.n, d * r.d)

def *(i: Int) = new Rational(n * i, d)

}

val r1 = new Rational(1, 2)

val r2 = new Rational(1, 4)

r1 * r2

r1.*(r2)

r1 * 2

2 * r1

Implicit conversions (1/2)

val r = new Rational(2)

2 * r

implicit def intToRational(i: Int) = new Rational(i, 1)

2 * r =>

intToRational(2) * r <=>

intToRational(2).*(r)

Implicit conversions (1/2)

val r = new Rational(2)

2 * r

implicit def intToRational(i: Int) = new Rational(i, 1)

2 * r =>

intToRational(2) * r <=>

intToRational(2).*(r)

Implicit conversions (1/2)

val r = new Rational(2)

2 * r

implicit def intToRational(i: Int) = new Rational(i, 1)

2 * r =>

intToRational(2) * r <=>

intToRational(2).*(r)

Implicit conversions (2/2)

Other examples:

1 to 5

(1 is converted to RichInt)

1 max 2

(1 is converted to RichInt)

-2.5 abs

(-2.5 is converted to RichDouble)

Map(

1 -> "a"

(1 is converted to ArrowAssoc[Int])

)

RichInt, RichDouble, ..., are called rich wrappers

Implicit conversions (2/2)

Other examples:

1 to 5 (1 is converted to RichInt)

1 max 2 (1 is converted to RichInt)

-2.5 abs (-2.5 is converted to RichDouble)

Map(

1 -> "a" (1 is converted to ArrowAssoc[Int])

)

RichInt, RichDouble, ..., are called rich wrappers

Implicit conversions (2/2)

Other examples:

1 to 5 (1 is converted to RichInt)

1 max 2 (1 is converted to RichInt)

-2.5 abs (-2.5 is converted to RichDouble)

Map(

1 -> "a" (1 is converted to ArrowAssoc[Int])

)

RichInt, RichDouble, ..., are called rich wrappers

Summary

I Operators - ordinary methods

I Method overloading - similar to Java

I Implicit conversions

. . . . . .

Objects and factory methods

Christian.Soderberg@cs.lth.se

29 maj 2012

. . . . . .

Objects

▸ An object defined with the keyword object (as opposed tothose created using new), is a singleton – this means that it isthe only member of its type.

▸ We use this kind of objects in two ways:

▸ as standalone objects – to use when we only need one objectof its kind, e.g. for writing main programs,

▸ as companion objects – to assist a class or trait.

. . . . . .

Objects

▸ An object defined with the keyword object (as opposed tothose created using new), is a singleton – this means that it isthe only member of its type.

▸ We use this kind of objects in two ways:

▸ as standalone objects – to use when we only need one objectof its kind, e.g. for writing main programs,

▸ as companion objects – to assist a class or trait.

. . . . . .

Objects

▸ An object defined with the keyword object (as opposed tothose created using new), is a singleton – this means that it isthe only member of its type.

▸ We use this kind of objects in two ways:▸ as standalone objects – to use when we only need one objectof its kind, e.g. for writing main programs,

▸ as companion objects – to assist a class or trait.

. . . . . .

Objects

▸ An object defined with the keyword object (as opposed tothose created using new), is a singleton – this means that it isthe only member of its type.

▸ We use this kind of objects in two ways:▸ as standalone objects – to use when we only need one objectof its kind, e.g. for writing main programs,

▸ as companion objects – to assist a class or trait.

. . . . . .

Companion objects

▸ For every class and trait, we can define an object with thesame name as the class or trait – it becomes its companionobject.

▸ A class or trait and its companion object can access eachother’s private members – but we must either import theobject, or explicitly name it as a prefix when we refer to it.

▸ Companion objects are a great place to put factory methodsand implicits.

. . . . . .

Companion objects

▸ For every class and trait, we can define an object with thesame name as the class or trait – it becomes its companionobject.

▸ A class or trait and its companion object can access eachother’s private members – but we must either import theobject, or explicitly name it as a prefix when we refer to it.

▸ Companion objects are a great place to put factory methodsand implicits.

. . . . . .

Companion objects

▸ For every class and trait, we can define an object with thesame name as the class or trait – it becomes its companionobject.

▸ A class or trait and its companion object can access eachother’s private members – but we must either import theobject, or explicitly name it as a prefix when we refer to it.

▸ Companion objects are a great place to put factory methodsand implicits.

. . . . . .

Rational numbers, again▸ Assume we have a class Rational:

class Rational(n: Int, val d: Int) {def +(other: Rational) = ...def -(other: Rational) = ......override def toString = ...

}

▸ We can define a companion object with a factory method andan implicit – it must be defined in the same file:

object Rational {def Rat(num: Int, denom: Int) = / / f ac tory

new Rational(num, denom)implicit def int2Rational(value: Int) =

Rat(value, 1)}

. . . . . .

Rational numbers, again▸ Assume we have a class Rational:

class Rational(n: Int, val d: Int) {def +(other: Rational) = ...def -(other: Rational) = ......override def toString = ...

}

▸ We can define a companion object with a factory method andan implicit – it must be defined in the same file:

object Rational {def Rat(num: Int, denom: Int) = / / f ac tory

new Rational(num, denom)implicit def int2Rational(value: Int) =

Rat(value, 1)}

. . . . . .

Using factory methods

▸ Using the methods of the companion object is simple, we justimport it:

import Rational._

val half = Rat(1, 2)val quarter = half / 2println(half * quarter)println(1 + half)

. . . . . .

Private constructors▸ We can easily enforce the use of our factory method:

object Rational {def Rat(num: Int, denom: Int) = { / / f ac tory

val g = gcd(num, denom)new Rational(num / g, denom / g)

}implicit def int2Rational(value: Int) = ...private def gcd(a: Int, b: Int): Int = ...

}

class Rational private (val num: Int,val denom: Int) {

import Rational._def +(other: Rational) = Rat(...)def -(other: Rational) = Rat(...)...

}

. . . . . .

. . . . . .

T H E E N D

Topic 4: InheritanceExtending, Overriding and Final

Jesper Pedersen Notander

Department of Computer ScienceLund University Faculty of Engineering

Learning ScalaSeminar 2

Contents Topics Summary

Contents

I Abstract and concrete classesI Simple inheritanceI Overriding membersI Polymorphism and dynamic bindingI Keywords: abstract, extends, override and final

Dept. of Computer Science/Learning Scala/Seminar 2/Topic 4/ Inheritance

Contents Topics Summary

Abstract and Concrete Classes Inheritance Overriding Polymorphism and Dynamic Binding

Abstract and Concrete Classes

I Concrete classes, "normal classes"I Defines members, e.g. val x: Int = 0;I Can be instantiatedI Must define inherited abstract members.

I Abstract classesI Defines membersI Cannot be instantiatedI Declares abstract members, e.g. val x: Int;

I Abstract classes are implemented by adding the keywordabstract to the class declaration, e.g.abstract class MyAbstractClass

Dept. of Computer Science/Learning Scala/Seminar 2/Topic 4/ Inheritance

Contents Topics Summary

Abstract and Concrete Classes Inheritance Overriding Polymorphism and Dynamic Binding

Abstract Members and Declarations

abstract class C(val p1: Int, private var p2: Int) {protected var f1: Int

private def m1(a: Int): Intdef m2: Int

}

I Fields and methods are declared in the body or the parameter list of theclass.

I Methods can be declared without brackets if they have no arguments.Thus, def m2: Int <=> val m2: Int, when accessing point ofview.

I The access modifier defines the visibility of the declaration:public Visible where the class is accessible, default (no modifier)

protected Visible in the class and its subclassesprivate Visible in the class

Dept. of Computer Science/Learning Scala/Seminar 2/Topic 4/ Inheritance

Contents Topics Summary

Abstract and Concrete Classes Inheritance Overriding Polymorphism and Dynamic Binding

Extending a Class

I To inherit from a class place the keyword extends after theclass name in the declaration of a class, followed by thename of the class to inherit from, e.g.class B(x: Int)extends A(x)...

Terminology: class B inherits class A, type B is a subtype of type A, class A is a

superclass of class B and class B is a subclass of class A

I All members of the superclass become members of thesubclass except:

I Private membersI Members with the same name as a member in the

subclass.

Dept. of Computer Science/Learning Scala/Seminar 2/Topic 4/ Inheritance

Contents Topics Summary

Abstract and Concrete Classes Inheritance Overriding Polymorphism and Dynamic Binding

Overriding Members

I When a subclass defines a member declared in asuperclass the subclass is said to override the member.

I Methods and fields share the same namespace and it isallowed to override a field with a method and vice versa.

I The modifier override is required when overriding aconcrete member, e.g.override def myfun(x: Int)= 0

Dept. of Computer Science/Learning Scala/Seminar 2/Topic 4/ Inheritance

Contents Topics Summary

Abstract and Concrete Classes Inheritance Overriding Polymorphism and Dynamic Binding

Example Overriding

abstract class A {def attr: Intdef fun: Int = 1

}

class B extends A {def attr = 0 // concrete definition of A.attroverride def fun = 2 // override of abstract A.fun

}

// override of abstract method A.attr with the field attrclass C( val attr: Int) extends A

scala> (new B).attrres13: Int = 0scala> (new B).funres14: Int = 2scala> (new C(10)).funres16: Int = 1scala> (new C(10)).attrres17: Int = 10

Dept. of Computer Science/Learning Scala/Seminar 2/Topic 4/ Inheritance

Contents Topics Summary

Abstract and Concrete Classes Inheritance Overriding Polymorphism and Dynamic Binding

Preventing Overrides

I Members can be prevented from being overridden bysubclasses by adding the final modifier.

class A { // subclasses of A cannot override xfinal def x = 1def y = 2

}

I A class can be prevented from being subclassed byplacing final in its declaration.

final class B { //class B cannot be subclasseddef x = 1def y = 2

}

Dept. of Computer Science/Learning Scala/Seminar 2/Topic 4/ Inheritance

Contents Topics Summary

Abstract and Concrete Classes Inheritance Overriding Polymorphism and Dynamic Binding

Subtyping Polymorphism

class A {def f = 1

}

class B extends A {pverride def f = 2

}

val a: A = new A()val b: A = new B() // polymorphism

I Polymorphism in this presentation refers to subtypingpolymorphism, which is the ability of a language to definesubtypes and refer to values of them using a reference witha supertype-

Dept. of Computer Science/Learning Scala/Seminar 2/Topic 4/ Inheritance

Contents Topics Summary

Abstract and Concrete Classes Inheritance Overriding Polymorphism and Dynamic Binding

Dynamic Binding

I The other part of polymorphism is dynamic binding, whichmeans that the method that is actually invoked whenaccess is determined by the runtime object of the object,e.g. a.f =>1 whereas b.f =>2 although both a and b areof type A.

Dept. of Computer Science/Learning Scala/Seminar 2/Topic 4/ Inheritance

Contents Topics Summary

Summary

I Abstract classes are declared with the keyword abstract and cancontain abstract members.

I Abstract members are fields or methods that are declared but notdefined in the class, e.g. def fun: Int;

I Inheritance is done by placing the keyword extends after the name ina class declaration, followed by the name of the super class, e.g.class B(args...)extends A(args...)

I A member overriding an inherited member must be declared with theoverride modifier, except if the inherited member is abstract.

I To prevent a method or a class to be overridden or subclassed themodifier final can be placed in the declaration, e.g.final class C or final def fun = 0

I Subtyping polymorphism is the ability to create subtypes and refer tothem with their super type. Method calls are bound dynamically to themethod in the runtime type of an object.

Dept. of Computer Science/Learning Scala/Seminar 2/Topic 4/ Inheritance

SCALA’S CLASS HIERARCHY AND PREDEF “One class to rule them all!”

Looks like:

“The Ring”

¨  Any is the superclass of all the classes. ¨  "Universal methods”

¨  Two subclasses: ¤ AnyVal ¤ AnyRef

AnyVal

¨  Parent of every built-in value class ¤ Java primitives + Unit

¨  Written as literals ¤ new Int : No can do… ¤ abstract, final

¨  Unit: ~void in Java ¤ Uninteresting method result

¨  Flat class space

AnyRef

¨  Mother of all reference classes ¤ On Java: alias for java.lang.Object!¤ Sidenote: trait ScalaObject is deprecated…

The poorlings

¨  Null: Subclass of every AnyRef ¤ null is it’s only value/instance

¨  Nothing: Can’t sink deeper… ¤ Subclass of everything ¤ No values

The deal with the dashed arrows…

¨  Views: Implicit conversions ¨  Predef:

¤ “The Predef object provides definitions that are accessible in all Scala compilation units without explicit qualification.” – scala-api

¤ Commonly used types ¤ Console I/O ¤ Assertions ¤  Implicit Conversions

FIN

def end(): Nothing = throw new EndOfPresentationException()

Control structures in Scala

CS Scala course 2012

Overview: control structures

• if • while • for • match • try • Function calls

+ Exercise

Main ideas

• Few built-in control structures – Others could be find in libraries

• They work much like imperative counterparts – But they also have values (most of them)

Main ideas (2)

• In Java: – Expressions have values – Statements carries out an action

• In Scala: – In Scala, almost ALL constructs have values

if

Can be written in Java style: if (n > 0) { r = r * n; n -= 1; }

if (2)

var s = 0 if (x > 0) s = 1 else s = -1 val s = if (x > 0) 1 else -1

• Better because of val

• Semicolon optional

But if returns a value!

if (3)

if statements must have some value => omitted else returns Unit (≈ Java void) if (x > 0) 1

equivalent to

if (x > 0) 1 else ()

Unit

while

Loops can be written in Java style while (n > 0) { r = r * n; n -= 1; } There is also the do ... while loop

while (2)

There is no: • break • continue Loops do NOT return a value => not used as often in Scala as in Java.

for

Scala has no direct analog of the Java for for (initialize; test; update)

for (i <- 1 to n)

the to method returns a Range (also: until)

for (i <- expr) <- to traverse all values of the right expression

for (2)

guard: an if inside the for Example: Filter out all numbers larger than 5

for (i <- expr; if i > 5 )

for (3)

for (...) yield • Creates a new collection of the same type as

the original • Contains the expressions after the yield, one

for each iteration of the loop.

Example: Double all elements larger than 5 val doubles = for (i <- expr; if i > 5 ) yield 2 * i

match

• Similar to switch statements • Returns a value • _ is used for default

val output = x match { case 1 => "one" case 2 => "two" case _ => "many" }

try

• Exceptions work as in Java – But you don’t need to declare that a function might

throw an exception

try { process(new FileReader(filename)) } catch { case _: FileNotFoundException => println(filename + " not found") case ex: IOException => ex.printStackTrace() } finally { … }

finally

Summary

• An if expression has a value • A block has a value—the value of its last expression • The Scala for loop is like an “enhanced” Java for loop • Semicolons are (mostly) optional • The void type is Unit • Avoid using return in a function • Exceptions work just like in Java or C++, but you use a “pattern matching” syntax for catch.

Topic 7 - Tuples, Placeholder Syntax,Closures, Tail Recursion Optimization

Alfred Theorin

Automatic Control

LTH

Tuples (Ch 17.5)

I Collection that holds a fixed number of items.

I Can hold items with different type.

Tuples (Ch 17.5)

Example

val myTuple = ("foo", 42, "bar")

// Tuple3[String, Int, String]

Tuples (Ch 17.5)

Example

val myTuple = ("foo", 42, "bar")

// Tuple3[String, Int, String]

Access

myTuple._1 // Returns "foo"

myTuple._2 // Returns 42

...

Tuples (Ch 17.5)

Example

val myTuple = ("foo", 42, "bar")

// Tuple3[String, Int, String]

Access

myTuple._1 // Returns "foo"

myTuple._2 // Returns 42

...

Assignment

val (a, b, c) = myTuple

Tuples (Ch 17.5)

I Useful for returning multiple items from a function.

I If the combination of items does not have a meaning, avoids

creating JavaBean classes.

I Too easy to use, if the combination has a meaning it is better

to create a class, e.g. don’t use (year, month, day) for

dates.

Placeholder Syntax (Ch 8.5)

Instead of specifying explicit parameter in function literals,

write .

List(1, 2, 3).foreach(i => println(i)) // Explicit

List(1, 2, 3).foreach(println(_)) // Placeholder

// Both print 1\n2\n3\n

Placeholder Syntax (Ch 8.5)

I Don’t have to come up with parameter names.

I One _ per parameter.

I Each parameter must only appear once.

I Cannot mix placeholder and explicit parameters.

Possible to give explicit type when necessary

val f = _ + _ // Wrong

val f = (_: Int) + (_: Int) // OK

Closures (Ch 8.7)

A function literal referring not only to passed parameters is

called a closure.

var more = 10

val f = (_: Int) + more

// Reference to captured variable more

println(f(2)) // Prints 12

more = 40

println(f(2)) // Prints 42

Closures (Ch 8.7)

Possible to manipulate captured variables

var sum = 0

List(1, 2, 3).foreach(sum += _)

println(sum) // Prints 6

Closures (Ch 8.7)

Always OK to refer to local variables, automatically uses heap

when necessary.

var more = 10

def makeIncreaser(more: Int) = (x: Int) => x + more

// Reference to passed parameter (stored on heap)

val f1 = makeIncreaser(more)

more = 20

val f2 = makeIncreaser(more)

f1(2) // Returns 12

f2(2) // Returns 22

Tail Recursion Optimization (Ch 8.9)

Coding functionally you might replace while-loops by recursion

def approximateLoop(initialGuess: Double): Double = {

var guess = initialGuess

while (!isGoodEnough(guess))

guess = improve(guess)

guess

}

def approximate(guess: Double): Double =

if isGoodEnough(guess)) guess

else approximate(improve(guess))

I Recursive call last, function called tail recursive.I Recursion replaced with jump by the Scala compiler.

Tail Recursion Optimization (Ch 8.9)

No new stack frames, might look weird in debugger

def boom(x: Int): Int =

if (x == 0) throw new Exception("boom!")

else boom(x - 1) // Tail recursive

boom(100)

java.lang.Exception: boom!

at .boom(<console>:9)

at .<init>(<console>:10)

I Can be disabled with compiler flag -g:notailcalls

Tail Recursion Optimization (Ch 8.9)

Only directly self-recursive calls are optimized.

def boom(x: Int): Int =

if (x == 0) throw new Exception("boom!")|

else 1 + boom(x - 1) // Not tail recursive

boom(2)

java.lang.Exception: boom!

at .boom(<console>:9)

at .boom(<console>:9)

at .boom(<console>:9)

at .<init>(<console>:10)

TOPIC 8.

CONTROL ABSTRACTIONCURRYING

BY-NAME PARAMETERS

BJÖRN A. JOHNSSON

CONTROL STRUCTURES

SCALA ONLY HAS 5 BUILT-IN CONTROL STRUCTURES:

if, while, for, try, match AND FUNCTION CALLS.

INSTEAD OF PREDEFINING MANY CONTROL STRUCTURES, SCALA GIVES THE ABILITY TO CREATE NEW ONES.

MADE POSSIBLE BY FUNCTION LITERALS.

scala> val printer = (toPrint: String) => println(toPrint)printer: String => Unit = <function1>

scala> printer(”Hello, world!”)Hello, world!

RECAP

CONTROL ABSTRACTION

HIGHER-ORDER-FUNCTIONS – FUNCTIONS THAT TAKE FUNCTIONS AS PARAMETERS

ENABLES THE CREATION OF CONTROL ABSTRACTIONS

BENEFITS:

REDUCES CODE DUPLICATION

SIMPLIFIES CLIENT CODE

object FileMatcher { private def filesHere = (new java.io.File(”.”)).listFiles

def filesMatching(query: String, matcher: (String, String) => Boolean) = for (file <- filesHere; if matcher(file.getName, query)) yield file}

CONTROL ABSTRACTIONEXAMPLE

object FileMatcher { private def filesHere = (new java.io.File(”.”)).listFiles

def filesMatching(query: String, matcher: (String, String) => Boolean) = for (file <- filesHere; if matcher(file.getName, query)) yield file

def filesEnding(query: String) = filesMatching(query, _.endsWith(_))}

CONTROL ABSTRACTIONEXAMPLE

object FileMatcher { private def filesHere = (new java.io.File(”.”)).listFiles

def filesMatching(query: String, matcher: (String, String) => Boolean) = for (file <- filesHere; if matcher(file.getName, query)) yield file

def filesEnding(query: String) = filesMatching(query, _.endsWith(_))

def filesContaining(query: String) = filesMatching(query, _.contains(_))}

CONTROL ABSTRACTIONEXAMPLE

object FileMatcher { private def filesHere = (new java.io.File(”.”)).listFiles

def filesMatching(query: String, matcher: (String, String) => Boolean) = for (file <- filesHere; if matcher(file.getName, query)) yield file

def filesEnding(query: String) = filesMatching(query, _.endsWith(_))

def filesContaining(query: String) = filesMatching(query, _.contains(_))

// ...more methods with omitted...}

CONTROL ABSTRACTIONEXAMPLE

CURRYING

A FUNCTIONAL PROGRAMMING TECHINQUE

”A CURRIED FUNCTION IS APPLIED TO MULTIPLE ARGUMENT LISTS, INSTEAD OF JUST ONE.”

scala> def plainOldSum(x: Int, y: Int) = x + yplainOldSum: (x: Int,y: Int)Int

”PLAIN OLD” FUNCTION

CURRYING

A FUNCTIONAL PROGRAMMING TECHINQUE

”A CURRIED FUNCTION IS APPLIED TO MULTIPLE ARGUMENT LISTS, INSTEAD OF JUST ONE.”

scala> def plainOldSum(x: Int, y: Int) = x + yplainOldSum: (x: Int,y: Int)Int

scala> plainOldSum(1, 2)res1: Int = 3

”PLAIN OLD” FUNCTION

CURRYING

A FUNCTIONAL PROGRAMMING TECHINQUE

”A CURRIED FUNCTION IS APPLIED TO MULTIPLE ARGUMENT LISTS, INSTEAD OF JUST ONE.”

scala> def plainOldSum(x: Int, y: Int) = x + yplainOldSum: (x: Int,y: Int)Int

scala> plainOldSum(1, 2)res1: Int = 3

scala> def curriedSum(x: Int)(y: Int) = x + ycurriedSum: (x: Int)(y: Int)Int

”PLAIN OLD” FUNCTION

CURRIED FUNCTION

CURRYING

A FUNCTIONAL PROGRAMMING TECHINQUE

”A CURRIED FUNCTION IS APPLIED TO MULTIPLE ARGUMENT LISTS, INSTEAD OF JUST ONE.”

scala> def plainOldSum(x: Int, y: Int) = x + yplainOldSum: (x: Int,y: Int)Int

scala> plainOldSum(1, 2)res1: Int = 3

scala> def curriedSum(x: Int)(y: Int) = x + ycurriedSum: (x: Int)(y: Int)Int

scala> curriedSum(1)(2)res1: Int = 3

”PLAIN OLD” FUNCTION

CURRIED FUNCTION

TRICK: INCREASE ”BUILT-IN” FEEL

CURLY BRACKETS CAN BE USED INSTEAD OF PARENTHESES WHEN INVOKING A METHOD THAT TAKES EXACLY ONE ARGUMENT.

scala> println (”Hello, world!”)Hello, world!

scala> println { ”Hello, world!” }Hello, world!

CURRYING USING CURLY BRACKETS

scala> def twice(x: Double, op: Double => Double) = op(op(x))twice: (x: Double, op: Double => Double)Double

CURRYING USING CURLY BRACKETS

scala> def twice(x: Double, op: Double => Double) = op(op(x))twice: (x: Double, op: Double => Double)Double

scala> twice(5, _ + 0.2) // Looks like normal invokationres1: Double = 5.4

CURRYING USING CURLY BRACKETS

scala> def twice(x: Double, op: Double => Double) = op(op(x))twice: (x: Double, op: Double => Double)Double

scala> twice(5, _ + 0.2) // Looks like normal invokationres1: Double = 5.4

scala> def twice(x: Double)(op: Double => Double) = op(op(x))twice: (x: Double)(op: Double => Double)Double

CURRYING USING CURLY BRACKETS

scala> def twice(x: Double, op: Double => Double) = op(op(x))twice: (x: Double, op: Double => Double)Double

scala> twice(5, _ + 0.2) // Looks like normal invokationres1: Double = 5.4

scala> def twice(x: Double)(op: Double => Double) = op(op(x))twice: (x: Double)(op: Double => Double)Double

scala> twice(5) { // Looks more like a ”built-in” control structure _ + 0.2}res1: Double = 5.4

BY-NAME PARAMETERS

CREATED BY GIVING THE PARAMETER A TYPE STARTING WITH => INSTEAD OF () =>

scala> def foo(predicate: () => Boolean) = predicate()foo: (predicate: () => Boolean)Boolean

STANDARD PARAMATER

BY-NAME PARAMETERS

CREATED BY GIVING THE PARAMETER A TYPE STARTING WITH => INSTEAD OF () =>

scala> def foo(predicate: () => Boolean) = predicate()foo: (predicate: () => Boolean)Boolean

scala> foo(() => 3 > 4) // A bit awkward...res1: Boolean = false

STANDARD PARAMATER

BY-NAME PARAMETERS

CREATED BY GIVING THE PARAMETER A TYPE STARTING WITH => INSTEAD OF () =>

scala> def foo(predicate: () => Boolean) = predicate()foo: (predicate: () => Boolean)Boolean

scala> foo(() => 3 > 4) // A bit awkward...res1: Boolean = false

scala> def foo(predicate: => Boolean) = predicatefoo: (predicate: => Boolean)Boolean

STANDARD PARAMATER

BY-NAME PARAMETER

BY-NAME PARAMETERS

CREATED BY GIVING THE PARAMETER A TYPE STARTING WITH => INSTEAD OF () =>

scala> def foo(predicate: () => Boolean) = predicate()foo: (predicate: () => Boolean)Boolean

scala> foo(() => 3 > 4) // A bit awkward...res1: Boolean = false

scala> def foo(predicate: => Boolean) = predicatefoo: (predicate: => Boolean)Boolean

scala> foo(3 > 4) // Better!res1: Boolean = false

STANDARD PARAMATER

BY-NAME PARAMETER

TIME FOR DISCUSSION?

ScalaPartially applied functions

andSpecial function call forms

Section 8.6 and 8.8 in Odersky

Intro

Partially applied functions

Placeholder Syntax

Function expression

No parameters

With parameters

Functions as argument

Special function call forms

Repeated arguments

Array

Named parameters

Default parameter values

Scala - Partially applied functions

Placeholder syntax

You can not only replace one parameter with the placeholder syntax “_”

myNumbers.foreach(println(_)) but also an entire parameter list:

myNumbers.foreach(println _)

written like this, it is an partially applied function. When passing arguments to a function, you apply the function to the parameters.

Intro

Partially applied functions

Placeholder Syntax

Function expression

No parameters

With parameters

Functions as argument

Special function call forms

Repeated arguments

Array

Named parameters

Default parameter values

Function expression - No parameters

Let’s say we have a function called triangleArea:

def triangleArea(b:Double, h:Double) = 0.5*b*h

we already know how to call itscala> triangleArea(4, 2)res0: Double = 4.0

We can now assign the partially applied function triangleArea _ to a variable:

val t = triangleArea _

Here no parameters are given.

scala> t(4,2)res1: Double = 4.0

Scala - Partially applied functions

Intro

Partially applied functions

Placeholder Syntax

Function expression

No parameters

With parameters

Functions as argument

Special function call forms

Repeated arguments

Array

Named parameters

Default parameter values

Function expression - With parameters

If you want to apply some of the parameters, you apply them like this:

val t2 = tringleArea(_: Double, 2)

Here one parameter is given.

scala> t2(4)res2: Double = 4.0

Scala - Partially applied functions

Intro

Partially applied functions

Placeholder Syntax

Function expression

No parameters

With parameters

Functions as argument

Special function call forms

Repeated arguments

Array

Named parameters

Default parameter values

Functions as argument

Using partially applied functions you can send a function value to another method that takes a function.

myNumbers.foreach(t2 _)

This can be written even more concisely by dropping the underscore

myNumbers.foreach(t2)

NOTE: Leaving out the underscore is only allowed when a function is expected.

val c = t2

val c = t2 _

Not OK

OK

Scala - Partially applied functions

Intro

Partially applied functions

Placeholder Syntax

Function expression

No parameters

With parameters

Functions as argument

Special function call forms

Repeated arguments

Array

Named parameters

Default parameter values

Special function call forms - Repeated arguments

To allow clients to pass variable length parameter lists you can write:

def echo(args: String*){println(“echo”)for(arg <- args) println(arg)}

scala> echo(“one”)echoone

scala> echo(“one”, “two”)echoonetwo

Scala - Special function call forms

Intro

Partially applied functions

Placeholder Syntax

Function expression

No parameters

With parameters

Functions as argument

Special function call forms

Repeated arguments

Array

Named parameters

Default parameter values

Repeated arguments - Array

However, it is not possible to pass an array of the right type to the function

val arr = Array(“What’s”, “up?”)

echo(arr) // Compiler error!

To call it on each of the elements in the array, write

scala>echo(arr:_*)echoWhat’sup?

Scala - Special function call forms

Intro

Partially applied functions

Placeholder Syntax

Function expression

No parameters

With parameters

Functions as argument

Special function call forms

Repeated arguments

Array

Named parameters

Default parameter values

Named parameters

def speed(distance: Float, time: Float): Float = distance/time

scala> speed(100, 10)res3: Float = 10.0

scala> speed(distance = 100, time = 10)res4: Float = 10.0

scala> speed(time = 10, distance = 100)res5: Float = 10.0

Scala - Special function call forms

Intro

Partially applied functions

Placeholder Syntax

Function expression

No parameters

With parameters

Functions as argument

Special function call forms

Repeated arguments

Array

Named parameters

Default parameter values

Intro

Partially applied functions

Placeholder Syntax

Function expression

No parameters

With parameters

Functions as argument

Special function call forms

Repeated arguments

Array

Named parameters

Default parameter values

Default parameter values

def printSomething(something: String, out: java.io.PrintStream = Console.out) {out.println(something)}

Usually, named parameters are used together with default parameters.

scala>printSomething(“something”)something

Scala - Special function call forms

// Traits in Scala

// Gustav Cedersj o

// Outline

// Part I: Interfaces

// Part II: Adding functionality

// Part III: Stackable modifications

// Part I: Interfaces

// Interface for a queue of integers

trait IntQueue {

def get(): Int

def put(x: Int)

}

// A simple implementation of IntQueue

import scala.collection.mutable.ArrayBuffer

class BasicIntQueue extends IntQueue {

private val buf = new ArrayBuffer[Int ]()

def get() = buf.remove (0)

def put(x: Int) { buf += x }

}

// Demo time!

val q1 = new BasicIntQueue

q1.put (1)

q1.put (2)

q1.get()

q1.get()

// Part II: Adding functionality

// We define a trait with new methods

trait MultiPut extends IntQueue {

def putAll(xs: Int*) {

for(x <- xs) { put(x) }

}

}

// How can we use the new trait?

// Make a new class and mix in the new trait

class MultiPutIntQueue extends

BasicIntQueue with MultiPut

val q2 = new MultiPutIntQueue

// ...or mix in the new trait on construction

val q3 = new BasicIntQueue with MultiPut

// Part III: Stackable modifications

// Double the value of the ints

trait Doubling extends IntQueue {

abstract override def put(x: Int) {

super.put(x+x)

}

}

// Demo time!

val q4 = new BasicIntQueue with Doubling

q4.put (1)

q4.put (2)

q4.get()

q4.get()

// What about more modifications?

trait Incrementing extends IntQueue {

abstract override def put(x: Int) {

super.put(x+1)

}

}

// We stack to modifications to the queue

val q5 = new BasicIntQueue with

Doubling with Incrementing

// In which order are the traits used?

q5.put (1)

q5.put (2)

q5.get()

q5.get()

// Of course we can also mix in

// the MultiPut trait

val q6 = new BasicIntQueue

with Doubling with Incrementing with MultiPut

q6.putAll (1,2,3)

q6.get()

q6.get()

q6.get()

// Exercise ...

Outro• This seminar:

– You have now tried these concepts from Ch 1 – 12 : classes, methods, objects, inheritance, Predef, control structures, tuples, placeholder, closures, traits

– Feedback on the course so far?• Seminar 3: June 14, at 13:15‐15:00 in E:2116

Invited Talks:– Görel: "The expression problem and Scala"– Kris: "Building a Scala library for JaCoP"– Jörn: "Scala Actors and Akka"– Jacek: "Functional programming in Scala«

• Seminar 3 concludes part 1 of the course (1.5 hp)– For 1.5 hp you need to read Ch 1‐12, do at least one exercises 

on each chapter, prepare presentations, and actively participate at all seminars (or negotiate alternatives with Björn Regnell).

top related