Kein Folientitel

Download Report

Transcript Kein Folientitel

Introduction to Scala
Introduction to Scala
Markus Völter
[email protected]
www.voelter.de
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
-1-
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
About me
•
•
Independent Consultant
•
Focus on
• Model-Driven Software
Development
• Software Architecture
• Middleware
Markus Völter
[email protected]
www.voelter.de
Based out of Heidenheim,
Germany
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
-2-
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
About this talk
•
This talk is an introduction to the Scala language.
•
Scala is a JVM-based, functional & object-oriented
language developed at EPFL, lead by Martin Odersky.
•
This introduction is based on tutorials and other
documentation by the Scala team.
• I am using their material with permission.
• Thanks to the Scala team for letting me use it!
•
The goals of this talk are to
• get you interested in Scala
• Show the power of functional programming
• Show where today’s language research is headed
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
-3-
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
This talk is not …
•
… based on huge amounts of hands-on experience.
• In contrast to most of my other talks where I primarily
talk about stuff I know inside out, I don’t have a whole lot
of experience using Scala.
•
… a complete reference of Scala features. I had to pick.
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
-4-
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Contents
•
General
•
Object Oriented Programming
•
Functional Programming
•
Other Features
•
Summary
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
-5-
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Contents
•
General
•
Object Oriented Programming
•
Functional Programming
•
Other Features
•
Summary
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
-6-
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Scala in a nutshell
•
Scala is object-oriented
•
Scala is functional
•
Scala is statically typed
•
Scala is extensible
•
Scala interoperates with Java and .NET
•
Information about Scala can be found at:
www.scala-lang.org
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
-7-
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Scala in a nutshell II
•
There is a Scala plugin for Eclipse that includes an
editor, compiler integration and a debugger.
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
-8-
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Scala in a nutshell III
•
Scala Hello World
object HelloWorld extends Application {
Console.println("Hello, world!");
}
•
However, as usual a Hello World does not tell us much
about the language. Therefore…
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
-9-
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Contents
•
General
•
Object Oriented Programming
•
Functional Programming
•
Other Features
•
Summary
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 10 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Classes
•
Basically as in Java, but…
• no return
• def keyword
• var keyword
• void => Unit
• constructor args =>
class args
• vals are read-only
•
variables
objects are top-level
singleton instances
class Point(xc: Int, yc: Int) {
var x: Int = xc
var y: Int = yc
def move(dx: Int, dy: Int): Unit = {
x = x + dx
y = y + dy
}
override def toString(): String
= "(" + x + ", " + y + ")";
}
object Classes {
def main(args: Array[String]): Unit = {
val pt = new Point(1, 2)
Console.println(pt)
pt.move(10, 10)
Console.println(pt)
}
}
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 11 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Automatic, User-Defined Type Coercions
•
An automatic type coercion is an implicit conversion
from a type to another, unrelated type if such a conversion
becomes necessary from the context.
class Frac(numerator: Int, denominator: Int) {
def +(that: Frac): Frac =
new Frac(numerator * that.denominator +
that.numerator * denominator,
denominator * that.denominator)
def neg: Frac = new Frac(-numerator, denominator)
def coerce: Float =
numerator.asInstanceOf[Float] / denominator
def coerce: Double =
numerator.asInstanceOf[Double] / denominator
}
•
You can now use a Frac where float or double is expected:
object CoercionTest extends Application {
Console.println(Math.sqrt(Frac(1,2)) + ", " +Math.sqrt(0.5))
}
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 12 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Traits
•
A trait is somewhat like an interface in Java, but can
be partially implemented:
trait Similarity {
def isSimilar(x: Any): Boolean
def isNotSimilar(x: Any): Boolean = !isSimilar(x)
}
•
Traits get integrated into classes using mixin class
composition. The “abstract” methods of the trait need to
be implemented in that class.
class Point(xc: Int, yc: Int) extends Similarity {
var x: Int = xc
var y: Int = yc
def isSimilar(obj: Any) =
obj.isInstanceOf[Point] &&
obj.asInstanceOf[Point].x == x
}
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 13 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Compound Types
•
Assume you have two traits:
trait Cloneable extends java.lang.Cloneable {
override def clone(): Cloneable = { super.clone(); this }
}
trait Resetable {
def reset: Unit
}
•
You can write use an (anonymous) compound type in
places where you expect an object to be Cloneable and
Resetable.
def cloneAndReset(obj: Cloneable with Resetable): Cloneable =
{
//...
}
•
Any number of … with … statements can be used.
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 14 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Abstract Types
•
Types can be abstract. One way of making them abstract
is to keep some type definitions open:
abstract class Buffer {
type T;
val element: T
}
•
Type definitions can be overridden in subclasses; type
bounds must be tightened.
abstract class SeqBuffer extends Buffer {
type U
type T <: Seq[U]
def length = element.length
}
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 15 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Abstract Types II
•
Types can be instantiated even if they are anonymous:
abstract class IntSeqBuffer extends SeqBuffer {
type U = Int
}
object AbstractTypeTest1 extends Application {
def newIntSeqBuf(elem1: Int, elem2: Int): IntSeqBuffer =
new IntSeqBuffer {
type T = List[U]
val element = List(elem1, elem2)
}
val buf = newIntSeqBuf(7, 8)
Console.println("length = " + buf.length)
Console.println("content = " + buf.element)
}
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 16 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Abstract Types III
•
An alternative notation uses type parameters (aka
Generics)
abstract class Buffer[+T] {
val element: T
}
abstract class SeqBuffer[U, +T <: Seq[U]] extends Buffer[T] {
def length = element.length
}
object AbstractTypeTest2 extends Application {
def newIntSeqBuf(e1: Int, e2: Int): SeqBuffer[Int, Seq[Int]] =
new SeqBuffer[Int, List[Int]] {
val element = List(e1, e2)
}
val buf = newIntSeqBuf(7, 8)
Console.println("length = " + buf.length)
Console.println("content = " + buf.element)
}
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 17 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Case Classes
•
Case classes are regular classes that
• export their constructor parameters
• provide a recursive decomposition mechanism via
pattern matching.
abstract class Term
case class Var(name: String) extends Term
case class Fun(arg: String, body: Term) extends Term
case class App(f: Term, v: Term) extends Term
•
Objects can be constructed without using new
Fun("x", Fun("y", App(Var("x"), Var("y"))))
•
Constructor vars can be accessed as if they were
public (r/o) variables; structural equals is also created.
val x = Var("x")
Console.println(x.name)
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 18 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Case Classes II
•
•
Case classes should be used if
recursive decomposition is
needed

def print(term: Term):
Unit = term match {
case Var(n) =>
Console.print(n)
case Fun(x, b) =>
Console.print("^"+x+".")
print(b)
You can also use deep matching
and guard clauses
case App(f, v) =>
Console.print("(")
print(f)
Console.print(" “)
print(v)
Console.print(")")
def isIdentityFun(term: Term):
Boolean = term match {
case Fun(x, Var(y)) if x == y => true
case _ => false
}
}
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 19 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
More General Pattern Matching
•
You cannot just match against case class instances, but
also against primitve values:
def matchTest(x: Int): String = x match {
case 1 => "one“
case 2 => "two“
case _ => "many“
}
•
… or against types:
def matchTest(x: Any): Any = x match {
case 1 => "one“
case "two" => 2
case y: Int => "scala.Int“
}
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 20 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Upper Type Bounds
•
An upper type bound restricts a type parameter to be a
subtype of another type.
trait Similar {
def isSimilar(x: Any): Boolean
}
case class MyInt(x: Int) extends Similar {
def isSimilar(m: Any): Boolean =
m.isInstanceOf[MyInt] &&
m.asInstanceOf[MyInt].x == x
}
object UpperBoundTest extends Application {
def findSimilar[T <: Similar](e: T, xs: List[T]): Boolean =
if (xs.isEmpty) false
else if (e.isSimilar(xs.head)) true
else findSimilar[T](e, xs.tail)
val list: List[MyInt] = List(MyInt(1), MyInt(2), MyInt(3))
Console.println(findSimilar[MyInt](MyInt(4), list))
Console.println(findSimilar[MyInt](MyInt(2), list))
}
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 21 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Contents
•
General
•
Object Oriented Programming
•
Functional Programming
•
Other Features
•
Summary
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 22 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Nested Functions
•
Just like in Good’Ol Pascal, functions can contain other,
nested functions.
object FilterTest extends Application {
def filter(xs: List[Int], threshold: Int) = {
def process(ys: List[Int]): List[Int] =
if (ys.isEmpty) ys
else if (ys.head < threshold) ys.head :: process(ys.tail)
else process(ys.tail)
process(xs)
}
Console.println(filter(List(1, 9, 2, 8, 3, 7, 4), 5))
}
•
This is very nice for defining recursive algorithms with
an “entry function”
• e.g. one that creates a list that you then pass around
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 23 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Anonymous Function Syntax
x: Int => x + 1
•
… is an anonymous function that computes the
successor of an integer
•
It is an abbreviation for the following anonymous
function
new Function1[Int, Int] {
def apply(x: Int): Int = x + 1;
}
•
Functions with multiple parameters are also possible
(x: Int, y: Int) => "(" + x + ", " + y + ")"
•
Function Types (i.e. signatures)
can be specified with a similar
syntax:
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
Int => Int
(Int, Int) => String
Unit => String
- 24 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Higher Order Functions
•
Higher order functions are functions either take other
functions as an argument or return other functions.
def apply(f: Int => String, v: Int) => f(v)
•
Something like apply is especially useful for working on
collections (“internal iterators”).
•
Methods are automatically coerced to functions if
required.
class Decorator(left: String, right: String) {
def layout[A](x: A) = left + x.toString() + right
}
object FunTest extends Application {
def apply(f: Int => String, v: Int) = f(v)
val decorator = new Decorator("[", "]")
Console.println(apply(decorator.layout, 7))
}
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 25 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Currying
•
If you call a function (method) with fewer
parameters than what it is formally defined with, the
the return value is a new function with the remaining
number of parameters.
object CurryTest extends Application {
def filter(xs: List[Int], p: Int => Boolean): List[Int] =
if (xs.isEmpty) xs
else if (p(xs.head)) xs.head :: filter(xs.tail, p)
else filter(xs.tail, p)
def modN(n: Int)(x: Int) = ((x % n) == 0)
val nums = List(1, 2, 3, 4, 5, 6, 7, 8)
Console.println(filter(nums, modN(2)))
Console.println(filter(nums, modN(3)))
}
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 26 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Contents
•
General
•
Object Oriented Programming
•
Functional Programming
•
Other Features
•
Summary
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 27 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Type Inference
•
Scala is statically typed, i.e. all type information is
known to the compiler.
•
However, you can still omit types iff the compiler can
automatically infer the type from the context.
object InferenceTest1 extends Application {
val x = 1 + 2 * 3 // the type of x is Int
val x:Int = 1 + 2 * 3 // same statement WITH types
val y = x.toString() // the type of y is String
val y:String = x.toString() // same statement WITH types
def succ(x: Int) = x + 1 // method succ returns Int values
def succ(x: Int): Int = x+1 // same statement WITH types
}
•
Note: in recursive methods, the type cannot be inferred
and thus must be given explicitly.
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 28 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Type Inference II
•
Type inference also works with generic types.
case class MyPair[A, B](x: A, y: B);
object InferenceTest3 extends Application {
val p = new MyPair(1, "scala") // type: MyPair[Int, String]
}
•
This is very useful. I hate the Java way, where I have to
write generics arguments all over the place.
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 29 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Lists
•
Lists are an essential data structure in Scala
• They are homogeneous (all elements same type)
• They can be nested
• Type parameter is optional (type inference!)
val fruit = List("apples", "oranges", "pears")
val nums : List[int] = List(1, 2, 3, 4)
val diag3: List[List[int]] = List(List(1, 0, 0), List(0, 1, 0),
List(0, 0, 1))val empty = List()
•
Lists are built from atomics: Nil and ::
• Lists can be representes as head :: tail
• :: is called cons, and is right associative
val fruit = "apples"
val nums = 1 :: 2 ::
val diag3 = (1 :: (0
(0 :: (1
(0 :: (0
val empty = Nil
:: ("oranges" :: ("pears" :: Nil))
4 :: 4 :: Nil
:: (0 :: Nil))) ::
:: (0 :: Nil))) ::
:: (1 :: Nil))) :: Nil
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 30 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Lists II
•
:: is defined as a case class, therefore you can use lists
in pattern matching contexts:
def isort(xs: List[int]): List[int] = xs match {
case List() => List()
case x :: xs1 => insert(x, isort(xs1))
}
def insert(x: int, xs: List[int]): List[int] = xs match {
case List() => List(x)
case y :: ys => if (x <= y) x :: xs else y :: insert(x, ys)
}
•
Several higher order methods are available on Lists:
abstract class List[a] { ...
def map[b](f: a => b): List[b] = this match {
case Nil => this
case x :: xs => f(x) :: xs.map(f)
}
def scaleList(xs: List[double], factor: double) =
xs map (x => x * factor)
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 31 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Sequence Comprehensions
•
Sequence comprehensions are basically a convenience
notation for creating lists.
object ComprehensionTest1 extends Application {
def even(from: Int, to: Int): List[Int] =
for (val i <- List.range(from, to); i % 2 == 0) yield i
Console.println(even(0, 20))
// List(0, 2, 4, 6, 8, 10, 12, 14, 16, 18)
}
•
More complex example:
object ComprehensionTest2 extends Application {
def foo(n: Int, v: Int): Iterator[Pair[Int, Int]] =
for (val i <- Iterator.range(0, n);
val j <- Iterator.range(i + 1, n); i + j == v)
yield Pair(i, j);
foo(20, 32) foreach {
case Pair(i, j) => Console.print("(" + i + ", " + j + “) ")
}
// (13, 19) (14, 18) (15, 17)
}
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 32 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Operators
•
Methods that take one parameter can be used as an
infix operator. Methods without parameters can be used as
postfix operators.
class
def
def
def
}
MyBool(x: Boolean) {
and(that: MyBool): MyBool = if (x) that else this
or(that: MyBool): MyBool = if (x) this else that
negate: MyBool = new MyBool(!x)
def not(x: MyBool) = x negate; // semicolon required here
def xor(x: MyBool, y: MyBool) = (x or y) and not(x and y)
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 33 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Automatic Type-Dependent Closure Construction
•
You can use parameterless function names as
parameters of methods.
• This is parameterless function name syntax:
(cond: => Boolean) // a function (name) that evaluates to Boolean
•
Once such a method is called,
• the actual parameters object TargetTest1 extends Application
are NOT evaluated!
def whileLoop(cond: => Boolean)
(body: => Unit): Unit =
• A nullary function is
if (cond) {
automatically defined
body
whileLoop(cond)(body)
(which encapsulates the
}
computation of the
}
parameter evaluation,
var i = 10
aka call-by-name)
whileLoop (i > 0) {
Console.println(i)
• This function is only
i = i 1
evaluated when its
}
accessed in the function
}
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 34 -
{
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Syntax Extension
•
Using automatic closure construction and operator syntax,
you can easily create new syntactic forms.
• Note how intermediate objects are created to which you
then subsequently apply an operator!
object TargetTest2 extends Application {
def loop(body: => Unit): LoopUnlessCond =
new LoopUnlessCond(body);
private class LoopUnlessCond(body: => Unit) {
def unless(cond: => Boolean): Unit = {
body
if (!cond) unless(cond);
}
}
var i = 10;
loop {
Console.println("i = " + i)
i = i 1
} unless (i == 0)
}
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 35 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Contents
•
General
•
Object Oriented Programming
•
Functional Programming
•
Other Features
•
Summary
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 36 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Summary
•
The combination of OO features and functional features
yields a very powerful and convincing language.
• … that is quite a bit bigger and more complex than Java
(“the PL1 of our time” – James Noble )
• It emphasizes today’s trend on language power (and
not library power, as in the last 10 years)
•
I am missing (compile time) meta programming.
Some kind of Converge-like macro facility would make this
language quite a bit more powerful.
• … as would a Weak type, on which typing would be
deferred to runtime – including methodNotFound
callbacks and the like.
•
Go to scala-lang.org, download Scala and play with it!
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 37 -
slides: © 2007 Markus Völter | examples: © Scala Team
Introduction to Scala
Contents
•
General
•
Object Oriented Programming
•
Functional Programming
•
Other Features
•
Summary
THE END.
Questions?
ingenieurbüro für sof twaretechnologie
w w w.vo el ter.d e
- 38 -
slides: © 2007 Markus Völter | examples: © Scala Team