Presentation is loading. Please wait.

Presentation is loading. Please wait.

Scala: How to make best use of functions and objects Philipp Haller Lukas Rytz Martin Odersky EPFL ACM Symposium on Applied Computing Tutorial.

Similar presentations


Presentation on theme: "Scala: How to make best use of functions and objects Philipp Haller Lukas Rytz Martin Odersky EPFL ACM Symposium on Applied Computing Tutorial."— Presentation transcript:

1 Scala: How to make best use of functions and objects Philipp Haller Lukas Rytz Martin Odersky EPFL ACM Symposium on Applied Computing Tutorial

2 2 Where it comes from Scala has established itself as one of the main alternative languages on the JVM. Prehistory: 1996 – 1997: Pizza 1998 – 2000: GJ, Java generics, javac ( “make Java better” ) Timeline: 2003 – 2006: The Scala “Experiment” 2006 – 2009: An industrial strength programming language ( “make a better Java” ) 19.06.2016Розподілені обчислення

3 3 19.06.2016Розподілені обчислення

4 4 Why Scala? 19.06.2016Розподілені обчислення

5 5 Scala is a Unifier Agile, with lightweight syntax Object-Oriented Scala Functional Safe and performant, with strong static typing 19.06.2016Розподілені обчислення

6 6 What others say: 19.06.2016Розподілені обчислення

7 7 “If I were to pick a language to use today other than Java, it would be Scala.” - James Gosling, creator of Java “Scala, it must be stated, is the current heir apparent to the Java throne. No other language on the JVM seems as capable of being a "replacement for Java" as Scala, and the momentum behind Scala is now unquestionable. While Scala is not a dynamic language, it has many of the characteristics of popular dynamic languages, through its rich and flexible type system, its sparse and clean syntax, and its marriage of functional and object paradigms.” - Charles Nutter, creator of JRuby “I can honestly say if someone had shown me the Programming in Scala book by Martin Odersky, Lex Spoon & Bill Venners back in 2003 I'd probably have never created Groovy.” - James Strachan, creator of Groovy. 19.06.2016Розподілені обчислення

8 8 Let’s see an example: 19.06.2016Розподілені обчислення

9 9 A class... public class Person { public final String name; public final int age; Person(String name, int age) { this.name = name; this.age = age; } class Person(val name: String, val age: Int) {}... in Java:... in Scala: 19.06.2016Розподілені обчислення

10 10... and its usage import java.util.ArrayList;... Person[] people; Person[] minors; Person[] adults; { ArrayList minorsList = new ArrayList (); ArrayList adultsList = new ArrayList (); for (int i = 0; i < people.length; i++) (people[i].age < 18 ? minorsList : adultsList).add(people[i]); minors = minorsList.toArray(people); adults = adultsList.toArray(people); }... in Java:... in Scala: val people: Array[Person] val (minors, adults) = people partition (_.age < 18) A simple pattern match An infix method call A function value 19.06.2016Розподілені обчислення

11 11 But there’s more to it 19.06.2016Розподілені обчислення

12 12 Embedding Domain-Specific Languages Scala’s flexible syntax makes it easy to define high-level APIs & embedded DSLs Examples: - Scala actors (the core of Twitter’s message queues) - specs, ScalaCheck - ScalaFX - ScalaQuery scalac’s plugin architecture makes it easy to typecheck DSLs and to enrich their semantics. // asynchronous message send actor ! message // message receive receive { case msgpat 1 => action 1 … case msgpat n => action n } 19.06.2016Розподілені обчислення

13 13 The Essence of Scala The work on Scala was motivated by two hypotheses: Hypothesis 1: A general-purpose language needs to be scalable; the same concepts should describe small as well as large parts. Hypothesis 2: Scalability can be achieved by unifying and generalizing functional and object- oriented programming concepts. 19.06.2016Розподілені обчислення

14 14 Why unify FP and OOP? Both have complementary strengths for composition: Object-oriented programming: Makes it easy to adapt and extend complex systems, using subtyping and inheritance, dynamic configurations, classes as partial abstractions. Functional programming: Makes it easy to build interesting things from simple parts, using higher-order functions, algebraic types and pattern matching, parametric polymorphism. 19.06.2016Розподілені обчислення

15 15 Scala Scala is an object-oriented and functional language which is completely interoperable with Java. (the.NET version is currently under reconstruction.) It removes some of the more arcane constructs of these environments and adds instead: (1) a uniform object model, (2) pattern matching and higher-order functions, (3) novel ways to abstract and compose programs. 19.06.2016Розподілені обчислення

16 16 Scala is interoperable Scala programs interoperate seamlessly with Java class libraries: –Method calls –Field accesses –Class inheritance –Interface implementation all work as in Java. Scala programs compile to JVM bytecodes. Scala’s syntax resembles Java’s, but there are also some differences. object Example1 { def main(args: Array[String]) { val b = new StringBuilder() for (i  0 until args.length) { if (i > 0) b.append(" ") b.append(args(i).toUpperCase) } Console.println(b.toString) } object instead of static members Array[String] instead of String[] Scala’s version of the extended for loop (use <- as an alias for  ) Arrays are indexed args(i) instead of args[i] 19.06.2016Розподілені обчислення

17 17 Scala is functional The last program can also be written in a completely different style: –Treat arrays as instances of general sequence abstractions. –Use higher-order functions instead of loops. object Example2 { def main(args: Array[String]) { println(args.map(_.toUpperCase).mkString(" ") } Arrays are instances of sequences with map and mkString methods. A closure which applies the toUpperCase method to its String argument map is a method of Array which applies the function on its right to each array element. mkString is a method of Array which forms a string of all elements with a given separator between them. 19.06.2016Розподілені обчислення

18 18 Scala is concise Scala’s syntax is lightweight and concise. Contributors: –semicolon inference, –type inference, –lightweight classes, –extensible API’s, –closures as control abstractions. Average reduction in LOC wrt Java: ≥ 2 due to concise syntax and better abstraction capabilities ***** Guy Steele: Scala led to a 4 times LOC reduction in the Fortress typechecker ***** var capital = Map( "US"  "Washington", "France"  "paris", "Japan"  "tokyo" ) capital += ( "Russia"  "Moskow" ) for ( (country, city)  capital ) capital += ( country  city.capitalize ) assert ( capital("Japan") == "Tokyo" ) 19.06.2016Розподілені обчислення

19 19 Scala is precise All code on the previous slide used library abstractions, not special syntax. Advantage: Libraries are extensible and give fine- grained control. Elaborate static type system catches many errors early. import scala.collection.mutable._ val capital = new HashMap[String, String] with SynchronizedMap[String, String] { override def default(key: String) = "?" } capital += ( "US"  "Washington", "France"  "Paris", "Japan"  "Tokyo" ) assert( capital("Russia") == "?" ) Specify kind of collections: mutable Specify map implementation: HashMap Specify map type: String to String Mixin trait SynchronizedMap to make capital map thread-safe Provide a default value: "?" 19.06.2016Розподілені обчислення

20 TRAITS 19.06.2016Розподілені обчислення 20

21 21 Big or small? Every language design faces the tension whether it should be big or small: –Big is good: expressive, easy to use. –Small is good: elegant, easy to learn. Can a language be both big and small? Scala’s approach: concentrate on abstraction and composition capabilities instead of basic language constructs. Scala addsScala removes + a pure object system - static members + operator overloading - special treatment of primitive types + closures as control abstractions - break, continue + mixin composition with traits - special treatment of interfaces + abstract type members - wildcards + pattern matching 19.06.2016Розподілені обчислення

22 22 Scala is extensible Guy Steele has formulated a benchmark for measuring language extensibility [Growing a Language, OOPSLA 98]: Can you add a type of complex numbers to the library and make it work as if it was a native number type? Similar problems: Adding type BigInt, Decimal, Intervals, Polynomials... scala> import Complex._ import Complex._ scala> val x = 1 + 1 * i x: Complex = 1.0+1.0*i scala> val y = x * i y: Complex = -1.0+1.0*i scala> val z = y + 1 z: Complex = 0.0+1.0*i 19.06.2016Розподілені обчислення

23 23 Implementing complex numbers object Complex { val i = new Complex(0, 1) implicit def double2complex(x: Double): Complex = new Complex(x, 0)... } class Complex(val re: Double, val im: Double) { def + (that: Complex): Complex = new Complex(this.re + that.re, this.im + that.im) def - (that: Complex): Complex = new Complex(this.re - that.re, this.im - that.im) def * (that: Complex): Complex = new Complex(this.re * that.re - this.im * that.im, this.re * that.im + this.im * that.re) def / (that: Complex): Complex = { val denom = that.re * that.re + that.im * that.im new Complex((this.re * that.re + this.im * that.im) / denom, (this.im * that.re - this.re * that.im) / denom) } override def toString = re+(if (im < 0) "-"+(-im) else "+"+im)+"*I"... } + is an identifier; can be used as a method name Infix operations are method calls: a + b is the same as a.+(b) Objects replace static class members Implicit conversions for mixed arithmetic Class parameters instead of fields+ explicit constructor 19.06.2016Розподілені обчислення

24 24 Implicits are Poor Man’s Type Classes /** A “type class” */ class Ord[T] { def < (x: T, y: T): Boolean } /** An “instance definition” */ implicit object intOrd extends Ord[Int] { def < (x: Int, y: Int) = x < y } /** Another instance definition */ implicit def listOrd[T](implicit tOrd: Ord[T]) = new Ord { def false case (Nil, _) => true case (x :: xs, y :: ts) => x < y || x == y && xs < ys } } 19.06.2016Розподілені обчислення

25 25 The Bottom Line When going from Java to Scala, expect at least a factor of 2 reduction in LOC Lines Of Code (software development).Lines Of Code (software development) But does it matter? Doesn’t Eclipse write these extra lines for me? This does matter. Eye-tracking experiments* show that for program comprehension, average time spent per word of source code is constant. So, roughly, half the code means half the time necessary to understand it. *G. Dubochet. Computer Code as a Medium for Human Communication: Are Programming Languages Improving? In 21st Annual Psychology of Programming Interest Group Conference, pages 174-187, Limerick, Ireland, 2009. 19.06.2016Розподілені обчислення

26 26 Part 2: The Scala Design 19.06.2016Розподілені обчислення

27 27 The Scala design Scala strives for the tightest possible integration of OOP and FP in a statically typed language. This continues to have unexpected consequences. Scala unifies –algebraic data types with class hierarchies, –functions with objects This gives a nice & rather efficient formulation of Erlang style actors 19.06.2016Розподілені обчислення

28 28 ADTs are class hierarchies Many functional languages have algebraic data types and pattern matching.  Concise and canonical manipulation of data structures. Object-oriented programmers object: –ADTs are not extensible, –ADTs violate the purity of the OO data model, –Pattern matching breaks encapsulation, –and it violates representation independence! 19.06.2016Розподілені обчислення

29 29 Pattern matching in Scala Here's a a set of definitions describing binary trees: And here's an inorder traversal of binary trees: This design keeps –purity: all cases are classes or objects. –extensibility: you can define more cases elsewhere. –encapsulation: only parameters of case classes are revealed. –representation independence using extractors [ECOOP 07]. abstract class Tree[T] case object Empty extends Tree[Nothing] case class Binary[T](elem: T, left: Tree[T], right: Tree[T]) extends Tree[T] def inOrder [T] ( t: Tree[T] ): List[T] = t match { case Empty => List() case Binary(e, l, r) => inOrder(l) ::: List(e) ::: inOrder(r) } The case modifier of an object or class means you can pattern match on it 19.06.2016Розподілені обчислення

30 30 Extractors... are objects with unapply methods.... similar to active patterns in F# unapply is called implicitly for pattern matching object Twice { def apply(x: Int) = x*2 def unapply(z: Int): Option[Int] = if (z%2==0) Some(z/2) else None } val x = Twice(21) x match { case Twice(y) => println(x+" is two times "+y) case _ => println("x is odd") } } 19.06.2016Розподілені обчислення

31 31 Functions are objects Scala is a functional language, in the sense that every function is a value. If functions are values, and values are objects, it follows that functions themselves are objects. The function type S => T is equivalent to scala.Function1[S, T] where Function1 is defined as follows : So functions are interpreted as objects with apply methods. For example, the anonymous successor function (x: Int ) => x + 1 is expanded to trait Function1[-S, +T] { def apply(x: S): T } new Function1[Int, Int] { def apply(x: Int): Int = x + 1 } 19.06.2016Розподілені обчислення

32 32 Why should I care? Since (=>) is a class, it can be subclassed. So one can specialize the concept of a function. An obvious use is for arrays, which are mutable functions over integer ranges. Another bit of syntactic sugaring lets one write: a(i) = a(i) + 2 for a.update(i, a.apply(i) + 2) class Array [T] ( length: Int ) extends (Int => T) { def length: Int =... def apply(i: Int): A =... def update(i: Int, x: A): unit =... def elements: Iterator[A] =... def exists(p: A => Boolean):Boolean =... } 19.06.2016Розподілені обчислення

33 33 Partial functions Another useful abstraction are partial functions. These are functions that are defined only in some part of their domain. What's more, one can inquire with the isDefinedAt method whether a partial function is defined for a given value. Scala treats blocks of pattern matching cases as instances of partial functions. This lets one write control structures that are not easily expressible otherwise. trait PartialFunction[-A, +B] extends (A => B) { def isDefinedAt(x: A): Boolean } 19.06.2016Розподілені обчислення

34 34 Example: Erlang-style actors Two principal constructs (adopted from Erlang): Send (!) is asynchronous; messages are buffered in an actor's mailbox. receive picks the first message in the mailbox which matches any of the patterns mspat i. If no pattern matches, the actor suspends. // asynchronous message send actor ! message // message receive receive { case msgpat 1 => action 1... case msgpat n => action n } A partial function of type PartialFunction[MessageType, ActionType] 19.06.2016Розподілені обчислення

35 35 A simple actor case class Data(b: Array[Byte]) case class GetSum(receiver: Actor) val checkSumCalculator = actor { var sum = 0 loop { receive { case Data(bytes) => sum += hash(bytes) case GetSum(receiver) => receiver ! sum } 19.06.2016Розподілені обчислення

36 36 Implementing receive Using partial functions, it is straightforward to implement receive: Here, self designates the currently executing actor, mailBox is its queue of pending messages, and extractFirst extracts first queue element matching given predicate. def receive [A] (f: PartialFunction[Message, A]): A = { self.mailBox.extractFirst(f.isDefinedAt) match { case Some(msg) => f(msg) case None => self.wait(messageSent) } 19.06.2016Розподілені обчислення

37 37 Library or language? A possible objection to Scala's library-based approach is: Why define actors in a library when they exist already in purer, more optimized form in Erlang? First reason: interoperability Another reason: libraries are much easier to extend and adapt than languages. Experience: Initial versions of actors used one thread per actor  lack of speed and scalability Later versions added a non- returning `receive’ called react which makes actors event- based. This gave great improvements in scalability. New variants using delimited continuations are being explored (this ICFP). 19.06.2016Розподілені обчислення

38 38 Scala cheat sheet (1): Definitions Scala method definitions: def fun(x: Int): Int = { result } def fun = result Scala variable definitions: var x: int = expression val x: String = expression Java method definition: int fun(int x) { return result } (no parameterless methods) Java variable definitions: int x = expression final String x = expression 19.06.2016Розподілені обчислення

39 39 Scala cheat sheet (2): Expressions Scala method calls: obj.meth(arg) or: obj meth arg Scala choice expressions: if (cond) expr1 else expr2 expr match { case pat 1 => expr 1.... case pat n => expr n } Java method call: obj.meth(arg) (no operator overloading) Java choice expressions, stats: cond ? expr1 : expr2 // expression if (cond) return expr1; // statement else return expr2; switch (expr) { case pat 1 : return expr 1 ;... case pat n : return expr n ; } // statement only 19.06.2016Розподілені обчислення

40 40 Scala cheat sheet (3): Objects and Classes Scala Class and Object class Sample(x: Int) { def instMeth(y: Int) = x + y } object Sample { def staticMeth(x: Int, y: Int) = x * y } Java Class with static class Sample { final int x; Sample(int x) { this.x = x } int instMeth(int y) { return x + y; } static int staticMeth(int x, int y) { return x * y; } } 19.06.2016Розподілені обчислення

41 41 Scala cheat sheet (4): Traits Scala Trait trait T { def abstractMeth(x: String): String def concreteMeth(x: String) = x+field var field = “!” } Scala mixin composition: class C extends Super with T Java Interface interface T { String abstractMeth(String x) (no concrete methods) (no fields) } Java extension + implementation: class C extends Super implements T 19.06.2016Розподілені обчислення

42 42 Part 3: Programming in Scala 19.06.2016Розподілені обчислення

43 43 Scala in serious use You'll see now how Scala's constructs play together in a realistic application. Task: Write a spreadsheet Start from scratch, don't use any parts which are not in the standard libraries You'll see that this can be done in under 200 lines of code. Nevertheless it demonstrates many aspects of scalability For comparison: Java demo: 850 LOC, MS Office 30Million LOC 19.06.2016Розподілені обчислення

44 44 Step 1: The main function Advantage of objects over statics: objects can inherit. Hence, can hide low-level fiddling necessary to set up a swing application. package scells import swing._ object Main extends SimpleSwingApplication { def top = new MainFrame { title = "ScalaSheet" contents += new SpreadSheet(100, 26) } 19.06.2016Розподілені обчислення

45 45 Step 2: The SpreadSheet class - view class SpreadSheet(val height: Int, val width: Int) extends ScrollPane { val cellModel = new Model(height, width) import cellModel.{cells, valueChanged} val table = new Table(height, width) { rowHeight = 25 autoResizeMode = Table.AutoResizeMode.Off showGrid = true gridColor = Color(150, 150, 150) def userData(row: Int, column: Int): String = { val v = this(row, column); if (v == null) "" else v.toString } override def render(isSelected: Boolean, hasFocus: Boolean, row: Int, column: Int) = if (hasFocus) new TextField(userData(row, column)) else new Label(cells(row)(column).toString) { halign = Orientation.right } reactions += { case event.TableChanged(table, firstRow, lastRow, column) => for (row <- firstRow to lastRow) cells(row)(column).formula = FormulaParsers.parse(userData(row, column)) case ValueChanged(cell) => markUpdated(cell.row, cell.column) } for (row <- cells; cell <- row) listenTo(cell) } val rowHeader = new ComponentList(0 until height map (_.toString)) { fixedCellWidth = 30 fixedCellHeight = table.rowHeight } viewportView = table; rowHeaderView = rowHeader } Property syntax; expands to method call rowHeight_=(25) This calls in turn jtable.setRowHeight(25) 19.06.2016Розподілені обчислення

46 46 Step 3: The SpreadSheet class - controller class SpreadSheet(val height: Int, val width: Int) extends ScrollPane { val cellModel = new Model(height, width) import cellModel.{cells, valueChanged} val table = new Table(height, width) { rowHeight = 25 autoResizeMode = Table.AutoResizeMode.Off showGrid = true gridColor = Color(150, 150, 150) def userData(row: Int, column: Int): String = { val v = this(row, column) if (v == null) "" else v.toString } override def render(isSelected: Boolean, hasFocus: Boolean, row: Int, column: Int) = if (hasFocus) new TextField(userData(row, column)) else new Label(cells(row)(column).toString) { halign = Orientation.right } reactions += { case event.TableChanged(table, firstRow, lastRow, column) => for (row <- firstRow to lastRow) cells(row)(column).formula = FormulaParsers.parse(userData(row, column)) case ValueChanged(cell) => markUpdated(cell.row, cell.column) } for (row <- cells; cell <- row) listenTo(cell) } val rowHeader = new ComponentList((0 until height) map (_.toString)) { fixedCellWidth = 30 fixedCellHeight = table.rowHeight } viewportView = table; owHeaderView = rowHeader } Import can be used anywhere, not just at top-level Events are objects, can pattern match on them. reactions property defines component behavior with closures. 19.06.2016Розподілені обчислення

47 47 Spreadsheet formulas We consider: -12.34 Number text Text label =expr Formulas, consisting of B12 Cell B12:C18 Range of cells add(A7,A4) Binary operation sum(A12:A14,A16) Vararg operation (no infix operations such as X+Y ) Formula expressions can nest, as in: =sum(mul(A4, 2.0), B7:B15)) 19.06.2016Розподілені обчислення

48 48 Step 4: Representing formulas internally trait Formula {} case class Coord(row: Int, column: Int) extends Formula { override def toString = ('A' + column).toChar.toString + row } case class Range(c1: Coord, c2: Coord) extends Formula { override def toString = c1.toString+":"+c2.toString } case class Number(value: Double) extends Formula { override def toString = value.toString } case class Textual(value: String) extends Formula { override def toString = value.toString } case class Application(function: String, arguments: List[Formula]) extends Formula { override def toString = function+arguments.mkString("(",", ",")") } object Empty extends Textual("") Case classes enable pattern matching B12 becomes Coord(12, 1) B0:B9 becomes Range(Coord(0, 1), Coord(9, 1) -12.34 becomes Number(-12.34d) ``Sales forecast'' becomes Textual("Sales forcast") add(A7, 42) becomes Application(Coord(7, 0), Number(42)) 19.06.2016Розподілені обчислення

49 49 A grammar for formulas number= -?\d+(\.\d*) ident= [A-Za-z_]\w* cell=[A-Za-Z]\d+ range= cell : cell application=ident ( expr (, expr)* ) expr=number | cell | range | application formula== expr textual=[^=].* 19.06.2016Розподілені обчислення

50 50 A grammar for formulas and their parsers number= -?\d+(\.\d*) """-?\d+(\.\d*)?""".r ident= [A-Za-z_]\w* """[a-zA-Z_]\w*""".r cell=[A-Za-Z]\d+ """ [A-Za-z]\d\d*""".r range= cell : cell cell~":"~cell application=ident ident~ ( expr (, expr)* ) "("~repsep(expr, ",")~")" expr=number number | cell | range | | cell application | range | application formula== expr "="~expr textual=[^=].* """[^=].*""".r 19.06.2016Розподілені обчислення

51 51 Step 5: Parsing formulas object FormulaParsers extends RegexParsers { def ident: Parser[String] = """[a-zA-Z_]\w*""".r def decimal: Parser[String] = """-?\d+(\.\d*)?""".r def cell: Parser[Coord] = """[A-Za-z]\d+""".r ^^ { s => val column = s.charAt(0) - 'A' val row = s.substring(1).toInt Coord(row, column) } def range: Parser[Range] = cell~":"~cell ^^ { case c1~":"~c2 => Range(c1, c2) } def number: Parser[Number] = decimal ^^ (s => Number(s.toDouble)) def application: Parser[Application] = ident~"("~repsep(expr, ",")~")" ^^ { case f~"("~ps~")" => Application(f, ps) } def expr: Parser[Formula] = application | range | cell | number def textual: Parser[Textual] = """[^=].*""".r ^^ Textual def formula: Parser[Formula] = number | textual | "=" ~> expr def parse(input: String): Formula = parseAll(formula, input) match { case Success(e, _) => e case f: NoSuccess => Textual("["+f.msg+"]") } This makes use of an internal DSL, much like the external Lex and Yacc. 19.06.2016Розподілені обчислення

52 52 Step 6: Evaluating formulas trait Evaluator { this: Model => val operations = new collection.mutable.HashMap[String, List[Double] => Double] def evaluate(e: Formula): Double = e match { case Number(v) => v case Textual(_) => 0 case Coord(row, column)=> cells(row)(column).value case Application(function, arguments) => val argvals = arguments flatMap evalList operations(function)(argvals) } private def evalList(e: Formula): List[Double] = e match { case Range(_, _) => references(e) map (_.value) case _ => List(evaluate(e)) } def references(e: Formula): List[Cell] = e match { case Coord(row, column) => List(cells(row)(column)) case Range(Coord(r1, c1), Coord(r2, c2)) => for (row <- (r1 to r2).toList; column <- c1 to c2) yield cells(row)(column) case Application(function, arguments) => arguments flatMap references case => List() } Evaluate by pattern matching on the kind of formula But how does Evaluator know about cells ? Scala's Self-type feature lets us assume the type of this in Evaluator is Model 19.06.2016Розподілені обчислення

53 53 Step 7: The spreadsheet Model class class Model(val height: Int, val width: int) extends Evaluator with Arithmetic { class Cell(row: Int, column: Int) extends Publisher { private var v: Double = 0 def value: Double = v def value_=(w: Double) { if (!(v == w || v.isNaN && w.isNaN)) { v = w publish(ValueChanged(this)) } private var e: Formula = Empty def formula: Formula = e def formula_=(e: Formula) { for (c <- references(formula)) deafTo(c) this.e = e for (c <- references(formula)) listenTo(c) value = evaluate(e) } reactions += { case ValueChanged(_) => value = evaluate(formula) } case class ValueChanged(cell: Cell) extends event.Event val cells = Array.fromFunction(new Cell(_, _))(width, height) } Property definitions make interesting things happen when variables are set 19.06.2016Розподілені обчислення

54 54 Lessons learned DSL's can help keep software short and clear: Parser combinators, swing components and reactions. Internal DSLs have advantages over external ones. Mixin composition + self types let you write fully re-entrant complex systems without any statics. Application complexity can be reduced by the right language constructs. To ensure you always have the right constructs, you need a language that's extensible and scalable. 19.06.2016Розподілені обчислення

55 55 But how long will it take me to switch? 19.06.2016Розподілені обчислення

56 56 100% 200% 0% 4-6 weeks8-12 weeks Learning Curves Scala Keeps familiar environment: : IDE’s: Eclipse, IDEA, Netbeans,... Tools: JavaRebel, FindBugs, Maven,... Libraries: nio, collections, FJ,... Frameworks; Spring, OSDI, J2EE,......all work out of the box.. Alex Payne, Twitter: “Ops doesn’t know it’s not Java” Productivity Alex McGuire, EDF, who replaced majority of 300K lines Java with Scala: “Picking up Scala was really easy.” “Begin by writing Scala in Java style.” “With Scala you can mix and match withwell.” your old Java.” “You can manage risk really 19.06.2016Розподілені обчислення

57 57 How to get started 100s of resources on the web. Here are three great entry points: Simply Scala Scalazine @ artima.com Scala for Java refugees 19.06.2016Розподілені обчислення

58 58 How to find out more Scala site: www.scala-lang.org Six books last year 19.06.2016Розподілені обчислення

59 59 Soon to come New release Scala 2.8, with –named and default parameters, –@specialized annotations for high performance numerical computations, –improved IDE plugin support, –and much more. New version on.NET with Visual Studio integration 19.06.2016Розподілені обчислення

60 60 Long term focus: Concurrency & Parallelism Our goal: establish Scala as the premier language for multicore programming. Actors gave us a head start. Actors as a library worked well because of Scala’s flexible syntax and strong typing. The same mechanisms can also be brought to bear in the development of other concurrency abstractions, such as: –parallel collections, –software transactional memory, –stream processing. 19.06.2016Розподілені обчислення

61 Introduction to Scala

62 What’s Scala and why should You Care? It’s language written by by Martin Odersky at EPFLIt’s language written by by Martin Odersky at EPFL (École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland Influenced by ML/Haskell, Java and other languages with better support for component softwarewith better support for component software It’s a scalable Programming language for component software with a focus is on abstraction, composition, and decomposition and not on primitivesIt’s a scalable Programming language for component software with a focus is on abstraction, composition, and decomposition and not on primitives It unifies OOP and functional programmingIt unifies OOP and functional programming It interoperates with Java and.NETIt interoperates with Java and.NET 62

63 63 Why Scala? (Coming from Java/C++) Runs on the JVM –Can use any Java code in Scala –Almost as fast as Java (within 10%) Much shorter code –Odersky reports 50% reduction in most code over Java –Local type inference Fewer errors –No Null Pointer problems More flexibility –As many public classes per source file as you want –Operator overloading

64 Getting Started in Scala 64 scala –Runs compiled scala code –Or without arguments, as an interpreter! scalac - compiles fsc - compiles faster! (uses a background server to minimize startup time) Go to scala-lang.org for downloads/documentation Read Scala: A Scalable Language (see http://www.artima.com/scalazine/articles/scalable- language.html )http://www.artima.com/scalazine/articles/scalable- language.html

65 Features of Scala Scala is both functional and object-oriented –every value is an object –every function is a value--including methods Scala is statically typed –includes a local type inference system: –in Java 1.5: Pair p = new Pair (1, "Scala"); new Pair (1, "Scala"); – in Scala: val p = new MyPair(1, "scala"); 65

66 Scala – The Interpreter Easiest way to get started with Scala is by using the Scala interpreter, which is an interactive “shell” for writing Scala expressions Simply type an expression into the interpreter and it will evaluate the expression and print the resulting value. $ scala This is an interpreter for Scala. Type in expressions to have them evaluated. Type :help for more information. scala> After you type an expression, such as 1 + 2, and hit return: scala> 1 + 2 The interpreter will print: unnamed0: Int = 3 This line includes: an automatically assigned or user-defined name to refer to the computed value (unnamed0) a colon (:) the type of the expression and its resulting value (Int) an equals sign (=) the value resulting from evaluating the expression (3) 66

67 More features Supports lightweight syntax for anonymous functions, higher-order functions, nested functions, currying ML-style pattern matching Integration with XML –can write XML directly in Scala program –can convert XML DTD into Scala class definitions Support for regular expression patterns 67

68 Other features Allows defining new control structures without using macros, and while maintaining static typing Any function can be used as an infix or postfix operator Can define methods named +, <= or :: 68

69 Automatic Closure Construction Allows programmers to make their own control structures Can tag the parameters of methods with the modifier def. When method is called, the actual def parameters are not evaluated and a no-argument function is passed 69

70 While loop example object TargetTest1 with Application { def loopWhile(def cond: Boolean)(def body: Unit): Unit = if (cond) { body; loopWhile(cond)(body); } var i = 10; loopWhile (i > 0) { Console.println(i); i = i – 1 Note: var/val Note: var/val } 70 Define loopWhile method Use it with nice syntax

71 Scala class hierarchy

72 Scala object system Class-based Single inheritance Can define singleton objects easily (no need for static which is not really OO) Traits, compound types, and views allow for more flexibility 72

73 73 Basic Scala Use var to declare variables: var x = 3; x += 4; Use val to declare values (final vars) val y = 3; y += 4; // error Notice no types, but it is statically typed var x = 3; x = “hello world”; // error Type annotations: var x : Int = 3;

74 74 Basic Scala Class instances val c = new IntCounter[String]; Accessing members (Look Ma no args!) println(c.size); // same as c.size() Defining functions: def foo(x : Int) { println(x == 42); } def bar(y : Int): Int = y + 42; // no braces // needed! def return42 = 42; // No parameters either!

75 75 Functions, Mapping, Filtering Defining lambdas – nameless functions (types sometimes needed) f is now a mapping int-> int val f = x :Int => x + 42; f is now a mapping int-> int A way to haul around stateClosures! A way to haul around state var y = 3; val g = {x : Int => y += 1; x+y; } Maps (and a cool way to do some functions) List(1,2,3).map(_+10).foreach(println) Filtering (and ranges!) 1 to 100 filter (_ % 7 == 3) foreach (println) –(Feels a bit like doing unix pipes?)

76 Classes and Objects trait Nat; object Zero extends Nat { def isZero: boolean = true; def pred: Nat = throw new Error("Zero.pred"); } class Succ(n: Nat) extends Nat { def isZero: boolean = false; def pred: Nat = n; } 76

77 Traits Similar to interfaces in Java They may have implementations of methods But can’t contain state Can be multiply inherited from 77

78 More on Traits Halfway between an interface and a class, called a trait. A class can incorporate as multiple Traits like Java interfaces but unlike interfaces they can also contain behavior, like classes. Also, like both classes and interfaces, traits can introduce new methods. Unlike either, the definition of that behavior isn't checked until the trait is actually incorporated as part of a class.

79 Example of traits trait Similarity { def isSimilar(x: Any): Boolean; def isNotSimilar(x: Any): Boolean = !isSimilar(x); } class Point(xc: Int, yc: Int) with Similarity { var x: Int = xc; var y: Int = yc; def isSimilar(obj: Any) = obj.isInstanceOf[Point] && obj.asInstanceOf[Point].x == x; } 79

80 Mixin class composition Basic inheritance model is single inheritance But mixin classes allow more flexibility class Point2D(xc: Int, yc: Int) { val x = xc; val y = yc; // methods for manipulating Point2Ds } class ColoredPoint2D(u: Int, v: Int, c: String) extends Point2D(u, v) { var color = c; def setColor(newCol: String): Unit = color = newCol; } 80

81 Mixin class composition example class Point3D(xc: Int, yc: Int, zc: Int) extends Point2D(xc, yc) { val z = zc; // code for manipulating Point3Ds } class ColoredPoint3D(xc: Int, yc: Int, zc: Int, col: String) extends Point3D(xc, yc, zc) with ColoredPoint2D(xc, yc, col); ColoredPoint2D Point2D Point3D ColoredPoint3D ColoredPoint2D

82 Mixin class composition Mixin composition adds members explicitly defined in ColoredPoint2D (members that weren’t inherited) Mixing a class C into another class D is legal only as long as D’s superclass is a subclass of C’s superclass. –i.e., D must inherit at least everything that C inherited Why? 82

83 Mixin class composition Remember that only members explicitly defined in ColoredPoint2D are mixin inherited So, if those members refer to definitions that were inherited from Point2D, they had better exist in ColoredPoint3D –They do, since ColoredPoint3D extends Point3D which extends Point2D 83

84 Views Defines a coercion from one type to another Similar to conversion operators in C++/C# trait Set { def include(x: int): Set; def include(x: int): Set; def contains(x: int): boolean def contains(x: int): boolean} def view(list: List) : Set = new Set { def include(x: int): Set = x prepend xs; def include(x: int): Set = x prepend xs; def contains(x: int): boolean = def contains(x: int): boolean = !isEmpty && (list.head == x || list.tail contains x) !isEmpty && (list.head == x || list.tail contains x)} 84

85 Views Views are inserted automatically by the Scala compiler If e is of type T then a view is applied to e if: –expected type of e is not T (or a supertype) –a member selected from e is not a member of T Compiler uses only views in scope Suppose xs : List and view above is in scope val s: Set = xs; xs contains x val s: Set =view(xs); val s: Set = view(xs); view(xs) contains x

86 Compound types motivation def cloneAndReset(obj: ?): Cloneable = { val cloned = obj.clone(); obj.reset; cloned } 86 trait Resetable { def reset: Unit; } trait Cloneable { def clone(); }

87 Compound types In Java, the “solution” is: interface CloneableAndResetable extends Cloneable, Resetable But if the original object did not use the CloneableAndResetable interface, it won’t work Scala solution: use compound types (also called intersection types) def cloneAndReset(obj: Cloneable with Resetable): Cloneable = {... } 87

88 Variance annotations class Array[a] { def get(index: int): a def set(index: int, elem: a): unit; } Array[String] is not a subtype of Array[Any] If it were, we could do this: val x = new Array[String](1); val y : Array[Any] = x; y.set(0, new FooBar()); // just stored a FooBar in a String array!

89 Variance Annotations Covariance is ok with functional data structures trait GenList[+T] { def isEmpty: boolean; def head: T; def tail: GenList[T] } object Empty extends GenList[All] { def isEmpty: boolean = true; def head: All = throw new Error("Empty.head"); def tail: List[All] = throw new Error("Empty.tail"); } class Cons[+T](x: T, xs: GenList[T]) extends GenList[T] { def isEmpty: boolean = false; def head: T = x; def tail: GenList[T] = xs } 89

90 Variance Annotations Can also have contravariant type parameters –Useful for an object that can only be written to Scala checks that variance annotations are sound –covariant positions: immutable field types, method results –contravariant: method argument types –Type system ensures that covariant parameters are only used covariant positions (similar for contravariant)

91 Types as members abstract class AbsCell { type T; val init: T; private var value: T = init; def get: T = value; def set(x: T): unit = { value = x } } def createCell : AbsCell { new AbsCell { type T = int; val init = 1 } } Clients of createCell cannot rely on the fact that T is int, since this information is hidden from them

92 Resources The Scala programming language home page (see http://www.scala-lang.org/ ) http://www.scala-lang.org/ The Scala mailing list (see http://listes.epfl.ch/cgi- bin/doc_en?liste=scala )http://listes.epfl.ch/cgi- bin/doc_en?liste=scala The Scala wiki (see http://scala.sygneca.com/ )http://scala.sygneca.com/ A Scala plug-in for Eclipse (see http://www.scala- lang.org/downloads/eclipse/index.html )http://www.scala- lang.org/downloads/eclipse/index.html A Scala plug-in for IntelliJ (see http://plugins.intellij.net/plugin/?id=1347 ) http://plugins.intellij.net/plugin/?id=1347 92

93 References The Scala Programming Language as presented by Donna Malayeri (see http://www.cs.cmu.edu/~aldrich/courses/819/slides/scala.ppt )http://www.cs.cmu.edu/~aldrich/courses/819/slides/scala.ppt The Scala Language Specification 2.7 (seehttp://www.scala-lang.org/docu/files/ScalaReference.pdf )http://www.scala-lang.org/docu/files/ScalaReference.pdf The busy Java developer's guide to Scala: Of traits and behaviorsUsing Scala's version of Java interfaces(see http://www.ibm.com/developerworks/java/library/j-scala04298.html ) http://www.ibm.com/developerworks/java/library/j-scala04298.html First Steps to Scala (in Scalazine) by Bill Venners, Martin Odersky, and Lex Spoon, May 9, 2007 (see http://www.artima.com/scalazine/articles/steps.html ) http://www.artima.com/scalazine/articles/steps.html 93


Download ppt "Scala: How to make best use of functions and objects Philipp Haller Lukas Rytz Martin Odersky EPFL ACM Symposium on Applied Computing Tutorial."

Similar presentations


Ads by Google