Ti1220 Lecture 2

  • 856 views
Uploaded on

Lecture 2 of course on concepts of programming languages at Delft University of Technology

Lecture 2 of course on concepts of programming languages at Delft University of Technology

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
856
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
15
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Functional ObjectsEelco Visser Delft http://twitter.com/TI1220 University of Technology Concepts of Programming Languages Challenge the future
  • 2. Recapgetting started with ScalaObject-Oriented Programming in Scala• Expressions• Immutable and mutable variables (val, var)• Function definitions• Classes and objects• Class members • instance variables • methods• Singleton objects B:6.1 TI 1220 - Lecture 2: Functional Objects 2
  • 3. Overviewtoday’s lectureNames• Binding, name spacesFunctional objects• Objects without mutable state• Defining operatorsBuilt-in Control Structures• If, While, For, Exceptions• Variable scope B:6.1 TI 1220 - Lecture 2: Functional Objects 3
  • 4. IConcept: Name Binding B:6.1 TI 1220 - Lecture 2: Functional Objects 4
  • 5. Binding Variable Identifiers name binding bindingdefining occurrence val msg = "Hello, " + "world!" println(msg) applied occurrence val variables cannot be rebound B:6.1 TI 1220 - Lecture 2: Functional Objects 5
  • 6. Binding Variable Identifiers name binding bindingdefining occurrence var greeting = "Hello, world!" greeting = "Leave me alone, world!"rebinding var variables can be rebound B:6.1 TI 1220 - Lecture 2: Functional Objects 6
  • 7. Binding Function Identifiers name binding bindingdefining occurrence def widthOfLength(s: String) = s.length.toString.length val maxWidth = widthOfLength(longestLine) applied occurrence B:6.1 TI 1220 - Lecture 2: Functional Objects 7
  • 8. Binding Class Identifiers name binding bindingdefining occurrence class ChecksumAccumulator { var sum = 0 } var acc = new ChecksumAccumulator var csa = new ChecksumAccumulator acc.sum = 3 csa = acc applied occurrence TI 1220 - Lecture 2: Functional Objects 8
  • 9. Rebinding vs Mutationname binding class ChecksumAccumulator { var sum = 0 } binding var acc = new ChecksumAccumulator var csa = new ChecksumAccumulator mutation acc.sum = 3 csa = acc rebinding TI 1220 - Lecture 2: Functional Objects 9
  • 10. Name Spacesname binding object foo { val foo : Int = 0 def foo(x : Int) = x + 1 } object bar { def bar() = foo.foo(foo.foo) } variables, functions, objects are in separate name spaces B:6.1 TI 1220 - Lecture 2: Functional Objects 10
  • 11. Substitutionname binding val msg = "Hello, " + "world!" println(msg) ? println("Hello, " + "world!") can we replace applied occurrence with bound expression/value? B:6.1 TI 1220 - Lecture 2: Functional Objects 11
  • 12. IIFunctional Objects B:6.1 TI 1220 - Lecture 2: Functional Objects 12
  • 13. Rational Numbersmathematical laws• Rational = Int x Int• Notation: numerator/denominator• Addition • example: 1/2 + 2/3 = 3/6 + 4/6 = (3 + 4)/6 = 7/6 • general: n1/d1 + n2/d2 = (n1*d2 + n2*d1) / (d1*d2)• Multiplication • n1/d1 + n2/d2 = (n1 * n2) / (d1 * d2)• Division • n1/d1 / n2/d2 = n1/d2 * d2/n2 B:6.1 TI 1220 - Lecture 2: Functional Objects 13
  • 14. Constructing a Rationalclass parametersclass Rational(n: Int, d: Int) { println("Created " + n + "/" + d)}scala> new Rational(1, 2)Created 1/2res0: Rational = Rational@2d83e895 B:6.2 TI 1220 - Lecture 2: Functional Objects 14
  • 15. Immutable Object Trade-offsAdvantages• easier reasoning• pass around freely (no risk of undesired mutations)• cannot be changed concurrently in two threads• immutable object make safe hashtable keysDisadvantages• copying large object graphs vs in-place update B:6.1 TI 1220 - Lecture 2: Functional Objects 15
  • 16. Reimplementing toStringoverriding methodsclass Rational(n: Int, d: Int) { override def toString = n + "/" + d}scala> val half = new Rational(1, 2)half: Rational = 1/2 B:6.3 TI 1220 - Lecture 2: Functional Objects 16
  • 17. Checking Preconditionsclass Rational(n: Int, d: Int) { require(d != 0) override def toString = n + "/" + d}scala> val half = new Rational(1, 0)java.lang.IllegalArgumentException: requirement failed B:6.4 TI 1220 - Lecture 2: Functional Objects 17
  • 18. Visibility of Class Parametersclass Rational(n: Int, d: Int) { require(d != 0) override def toString = n + "/" + d def add(that: Rational): Rational = new Rational(n * that.d + that.n * d, d * that.d)}$ fsc Rational.scalaRational.scala:5: error: value d is not a member of Rational new Rational(n * that.d + that.n * d, d * that.d) ^Rational.scala:5: error: value d is not a member of Rational new Rational(n * that.d + that.n * d, d * that.d) ^two errors found B:6.5 TI 1220 - Lecture 2: Functional Objects 18
  • 19. Adding Fieldsclass Rational(n: Int, d: Int) { require(d != 0) val numer: Int = n val denom: Int = d override def toString = numer + "/" + denom def add(that: Rational): Rational = new Rational( numer * that.denom + that.numer * denom, denom * that.denom)}scala> new Rational(1,2) add new Rational(2,3)res0: Rational = 7/6 B:6.5 TI 1220 - Lecture 2: Functional Objects 19
  • 20. Non-Functional Objectsdestructive updateclass ImperativeRational(n: Int, d: Int) { require(d != 0) var numer: Int = n var denom: Int = d override def toString = numer + "/" + denom def add(that: ImperativeRational) { numer = numer * that.denom + that.numer * denom; denom = denom * that.denom; }} scala> val half = new ImperativeRational(1, 2) half: ImperativeRational = 1/2 scala> val twothirds = new ImperativeRational(2,3) twothirds: ImperativeRational = 2/3 scala> half.add(twothirds) scala> half res1: ImperativeRational = 7/6 B:6.1 TI 1220 - Lecture 2: Functional Objects 20
  • 21. Self Referencesthisdef lessThan(that: Rational) = this.numer * that.denom < that.numer * this.denomdef max(that: Rational) = if (this.lessThan(that)) that else this B:6.6 TI 1220 - Lecture 2: Functional Objects 21
  • 22. Auxiliary Constructorsclass Rational(n: Int, d: Int) { require(d != 0) val numer = n val denom = d def this(n: Int) = this(n, 1) // auxiliary constructor ...}scala> new Rational(6)res1: Rational = 6/1 B:6.7 TI 1220 - Lecture 2: Functional Objects 22
  • 23. Private Fields and Methodsclass Rational(n: Int, d: Int) { require(d != 0) private val g = gcd(n.abs, d.abs) val numer = n / g val denom = d / g ... private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b)}scala> new Rational(6,42)res1: Rational = 1/7 B:6.7 TI 1220 - Lecture 2: Functional Objects 23
  • 24. Defining Operatorsuse functions as infix operatorsdef add(that: Rational): Rational = new Rational(numer * that.denom + that.numer * denom, denom * that.denom)scala> new Rational(1,2).add(new Rational(2,3))res0: Rational = 7/6scala> new Rational(1,2) add new Rational(2,3)res0: Rational = 7/6 B:6.7 TI 1220 - Lecture 2: Functional Objects 24
  • 25. Invoking Operatorsoperator call is method call B:6.7 TI 1220 - Lecture 2: Functional Objects 25
  • 26. Defining Operatorsoperator identifiersdef +(that: Rational): Rational = new Rational(numer * that.denom + that.numer * denom, denom * that.denom)def *(that: Rational): Rational = new Rational(numer * that.numer, denom * that.denom)scala> val d = a + b * cd: Rational = 11/14scala> val d = a.+(b.*(c))d: Rational = 11/14scala> val d = a * b + cd: Rational = 16/21scala> val d = (a.*(b)).+(c)d: Rational = 16/21 B:6.7 TI 1220 - Lecture 2: Functional Objects 26
  • 27. Identifierslexical syntaxAlphanumeric identifier• identifier: [$A-Za-z_][$A-Za-z_0-9]* ($ reserved for Scala compiler)• camel-case convention: toString, HashSetOperator identifier• Unicode set of mathematical symbols(Sm) or other symbols(So), or to the 7-bit ASCII characters that are not letters, digits, parentheses, square brackets, curly braces, single or double quote, or an underscore, period,semi-colon, comma, or back tick character.Literal Identifier• arbitrary string enclosed in back ticks (` . . . `). B:6.1 TI 1220 - Lecture 2: Functional Objects 27
  • 28. Method Overloadingfor different argument types def *(that: Rational): Rational = new Rational(numer * that.numer, denom * that.denom) def *(i: Int): Rational = new Rational(numer * i, denom) scala> val c = new Rational(3,7) c: Rational = 3/7 scala> c * 2 res1: Rational = 6/7 B:6.1 TI 1220 - Lecture 2: Functional Objects 28
  • 29. Method Overloadingdoes not apply to this def *(that: Rational): Rational = new Rational(numer * that.numer, denom * that.denom) def *(i: Int): Rational = new Rational(numer * i, denom) scala> 2 * c <console>:7: error: overloaded method value * with alternatives: (Double) Double <and> (Float)Float <and> (Long)Long <and> (Int)Int <and> (Char)Int <and> (Short)Int <and> (Byte)Int cannot be applied to (Rational) 2 * c ^ B:6.1 TI 1220 - Lecture 2: Functional Objects 29
  • 30. Implicit Conversionsdef *(that: Rational): Rational = new Rational(numer * that.numer, denom * that.denom)def *(i: Int): Rational = new Rational(numer * i, denom)implicit def intToRational(x: Int) = new Rational(x)scala> 2 * cres4: Rational = 6/7 B:6.1 TI 1220 - Lecture 2: Functional Objects 30
  • 31. Summaryfunctional objectsImmutable objects• class parameters• immutable fields (val)• methods don’t change object, but return valueNatural, concise notation• methods as infix operators, operator identifiers• method overloading• implicit conversion B:6.1 TI 1220 - Lecture 2: Functional Objects 31
  • 32. Exam QuestionHow many Rational objects are created while executing:class Rational(n: Int, d: Int) { require(d != 0) val numer: Int = n val denom: Int = d override def toString = numer + "/" + denom def +(that: Rational): Rational = new Rational( numer * that.denom + that.numer * denom, denom * that.denom)}var half = new Rational(1,2)half = half + half + half(a) 1(b) 2(c) 3(d) 4 TI1220 - Introduction 32
  • 33. coffee break B:6.1 TI 1220 - Lecture 2: Functional Objects 33
  • 34. IIBuilt-in Control Structures B:6 TI 1220 - Lecture 2: Functional Objects 34
  • 35. Control-Flow StructuresControl-Flow Structures• ordering execution• choice, iteration, exceptionFunctional Control Structures• can be used as expression• return a valueMinimal set of built-in control structures• control abstraction using function literals (next week) B:6.1 TI 1220 - Lecture 2: Functional Objects 35
  • 36. If Expressionsconditional choicevar filename = "default.txt"if (!args.isEmpty) imperative style filename = args(0)val filename = if (!args.isEmpty) args(0) functional style else "default.txt" B:7.1 TI 1220 - Lecture 2: Functional Objects 36
  • 37. Equational Reasoningreplace equals by equalsval filename = if (!args.isEmpty) args(0) else "default.txt"println(filename)println(if (!args.isEmpty) args(0) else "default.txt") B:7.1 TI 1220 - Lecture 2: Functional Objects 37
  • 38. Equational Reasoningreplace equals by equalsval x = e; f(x) <=> f(e)if e has no side effects B:7.1 TI 1220 - Lecture 2: Functional Objects 38
  • 39. While Loopsiterationdef gcdLoop(x: Long, y: Long): Long = { var a = x var b = y while (a != 0) { val temp = a a = b % a b = temp } b} B:7.2 TI 1220 - Lecture 2: Functional Objects 39
  • 40. Do-While Loopsiterationvar line = ""do { line = readLine() println("Read: " + line)} while (line != "") B:7.2 TI 1220 - Lecture 2: Functional Objects 40
  • 41. Assignment has Type Unitvar line = ""while ((line = readLine()) != "") // This doesn’t work! println("Read: " + line) B:7.2 TI 1220 - Lecture 2: Functional Objects 41
  • 42. Iteration vs Recursion def gcd(x: Long, y: Long): Long = if (y == 0) x else gcd(y, x % y)def gcdLoop(x: Long, y: Long): Long = { var a = x var b = y while (a != 0) { val temp = a a = b % a b = temp } b} B:7.2 TI 1220 - Lecture 2: Functional Objects 42
  • 43. For Expressionsfunctional iterationval filesHere = (new java.io.File(".")).listFilesfor (file <- filesHere) println(file) B:7.3 TI 1220 - Lecture 2: Functional Objects 43
  • 44. Rangesiterating over sequence of numbersscala> for (i <- 1 to 4) | println("Iteration " + i)Iteration 1Iteration 2Iteration 3Iteration 4// Not common in Scala...for (i <- 0 to filesHere.length - 1) println(filesHere(i)) B:7.3 TI 1220 - Lecture 2: Functional Objects 44
  • 45. Filteringiterating over subset of a collectionfor (file <- filesHere) if (file.getName.endsWith(".scala")) println(file)for (file <- filesHere if file.getName.endsWith(".scala")) println(file) B:6.1 TI 1220 - Lecture 2: Functional Objects 45
  • 46. Multiple Filtersfor ( file <- filesHere if file.isFile; if file.getName.endsWith(".scala")) println(file) B:7.3 TI 1220 - Lecture 2: Functional Objects 46
  • 47. Nested Iterationdef fileLines(file: java.io.File) = scala.io.Source.fromFile(file).getLines.toListdef grep(pattern: String) = for ( file <- filesHere if file.getName.endsWith(".scala"); line <- fileLines(file) if line.trim.matches(pattern) ) println(file + ": " + line.trim)grep(".*gcd.*") B:7.3 TI 1220 - Lecture 2: Functional Objects 47
  • 48. Mid-Stream Variable Bindingdef grep(pattern: String) = for { file <- filesHere if file.getName.endsWith(".scala") line <- fileLines(file) trimmed = line.trim if trimmed.matches(pattern) } println(file + ": " + trimmed)grep(".*gcd.*") B:7.3 TI 1220 - Lecture 2: Functional Objects 48
  • 49. Producing a New Collectionyielddef scalaFiles = for { file <- filesHere if file.getName.endsWith(".scala") } yield file B:7.3 TI 1220 - Lecture 2: Functional Objects 49
  • 50. Composing filtersval forLineLengths = for { file <- filesHere if file.getName.endsWith(".scala") line <- fileLines(file) trimmed = line.trim if trimmed.matches(".*for.*") } yield trimmed.length B:7.3 TI 1220 - Lecture 2: Functional Objects 50
  • 51. Throwing Exceptionsexception handlingval half = if (n % 2 == 0) n / 2 else throw new RuntimeException("n must be even") B:7.4 TI 1220 - Lecture 2: Functional Objects 51
  • 52. Catching Exceptionsexception handlingimport java.io.FileReaderimport java.io.FileNotFoundExceptionimport java.io.IOExceptiontry { val f = new FileReader("input.txt") // Use and close file} catch { case ex: FileNotFoundException => // Handle missing file case ex: IOException => // Handle other I/O error} B:7.4 TI 1220 - Lecture 2: Functional Objects 52
  • 53. Finallyexception handlingimport java.io.FileReaderval file = new FileReader("input.txt")try { // Use the file} finally { file.close() // Be sure to close the file} B:7.4 TI 1220 - Lecture 2: Functional Objects 53
  • 54. Yielding a Valueexception handlingimport java.net.URLimport java.net.MalformedURLExceptiondef urlFor(path: String) = try { new URL(path) } catch { case e: MalformedURLException => new URL("http://www.scalalang.org") } B:7.4 TI 1220 - Lecture 2: Functional Objects 54
  • 55. Match Expressionschoosing between actionsval firstArg = if (args.length > 0) args(0) else ""firstArg match { case "salt" => println("pepper") case "chips" => println("salsa") case "eggs" => println("bacon") case _ => println("huh?")} B:7.5 TI 1220 - Lecture 2: Functional Objects 55
  • 56. Match Expressionschoosing between valuesval firstArg = if (!args.isEmpty) args(0) else ""val friend = firstArg match { case "salt" => "pepper" case "chips" => "salsa" case "eggs" => "bacon" case _ => "huh?" }println(friend) B:7.5 TI 1220 - Lecture 2: Functional Objects 56
  • 57. Break and Continue in Javanot in Scalaint i = 0; // This is Javaboolean foundIt = false;while (i < args.length) { if (args[i].startsWith("")) { i = i + 1; continue; } if (args[i].endsWith(".scala")) { foundIt = true; break; } i = i + 1;} B:7.6 TI 1220 - Lecture 2: Functional Objects 57
  • 58. Replace Break/Continue with If ...var i = 0var foundIt = falsewhile (i < args.length && !foundIt) { if (!args(i).startsWith("")) { if (args(i).endsWith(".scala")) foundIt = true } i = i + 1} B:7.6 TI 1220 - Lecture 2: Functional Objects 58
  • 59. ... or with Recursiondef searchFrom(i: Int): Int = if (i >= args.length) 1 else if (args(i).startsWith("")) searchFrom(i + 1) else if (args(i).endsWith(".scala")) i else searchFrom(i + 1)val i = searchFrom(0) B:7.6 TI 1220 - Lecture 2: Functional Objects 59
  • 60. Variable Scopealmost identical to JavaVariables are declared in a scope• { var j = 1; ... }Inner scopes shadow variables in outer scopes• { var j = 1; { var j = 2; ... } } B:7.7 TI 1220 - Lecture 2: Functional Objects 60
  • 61. Multiplication Table$ scala printmultitable.scala 1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40 5 10 15 20 25 30 35 40 45 50 6 12 18 24 30 36 42 48 54 60 7 14 21 28 35 42 49 56 63 70 8 16 24 32 40 48 56 64 72 80 9 18 27 36 45 54 63 72 81 90 10 20 30 40 50 60 70 80 90 100 B:6.1 TI 1220 - Lecture 2: Functional Objects 61
  • 62. def printMultiTable() { var i = 1 // only i in scope here while (i <= 10) { var j = 1 // both i and j in scope here while (j <= 10) { val prod = (i * j).toString // i, j, and prod in scope here var k = prod.length // i, j, prod, and k in scope here while (k < 4) { print(" ") k += 1 } print(prod) j += 1 } // i and j still in scope; prod and k out of scope println() i += 1 } // i still in scope; j, prod, and k out of scope} B:7.7 TI 1220 - Lecture 2: Functional Objects 62
  • 63. Refactoring Imperative-Style Code// Returns a row as a sequencedef makeRowSeq(row: Int) = for (col <- 1 to 10) yield { val prod = (row * col).toString val padding = " " * (4 - prod.length) padding + prod }// Returns a row as a stringdef makeRow(row: Int) = makeRowSeq(row).mkString// Returns table as a string with one row per linedef multiTable() = { val tableSeq = // a sequence of row strings for (row <- 1 to 10) yield makeRow(row) tableSeq.mkString("n")} B:6.1 TI 1220 - Lecture 2: Functional Objects 63
  • 64. VIISummary Term Rewriting 64
  • 65. Summarylessons learnedFunctional Objects• immutable objects• operations create new objectsFunctional Control Structures• return a value• have a type• can be used as expressions TI 1220 - Lecture 2: Functional Objects 65
  • 66. Literaturerequired readingProgramming in Scala• Chapter 6: Functional Objects• Chapter 7: Built-in Control Structures TI 1220 - Lecture 2: Functional Objects 66
  • 67. Exercises Week 2complex numbersScala Test• using unit testing framework to define executable testsComplex numbers• define class to represent complex numbers• define testsNote: all assignments should be done individually! B:6.1 TI 1220 - Lecture 2: Functional Objects 67
  • 68. http://www.scala-lang.org/api/current/index.html TI 1220 - Lecture 2: Functional Objects 68
  • 69. Scala Style Guideformatting rulesindentation: 2 spaces http://www.codecommit.com/scala-style-guide.pdf B:6.1 TI 1220 - Lecture 2: Functional Objects 69
  • 70. Outlookcoming nextLecture 3: Functions & Closures• Chapters 8, 9Lecture 4: List Programming• Chapters 15, 16, 17Lecture 5: Trees• Chapters 26, 22, 23Lab Week 2• Complex numbers in Scala B:6.1 TI 1220 - Lecture 2: Functional Objects 70
  • 71. Exam Question (Week 1)What happens when we execute the following code:val greetStrings = new Array[String](3)greetStrings(0) = "Hello"greetStrings(1) = ", "greetStrings(2) = "world!n"(a) Error: greetStrings is an immutable variable that cannot be assigned to(b) Error: Array is a immutable data structure that cannot be assigned to(c) No error: greetStrings is a mutable variable that can be assigned to(d) No error: Array is a mutable data structure that can be assigned to TI1220 - Introduction 71
  • 72. Exam Question (Week 1)What happens when we execute the following code:val greetStrings = new Array[String](3)greetStrings(0) = "Hello"greetStrings(1) = ", "greetStrings(2) = "world!n"(a) Error: greetStrings is an immutable variable that cannot be assigned to(b) Error: Array is a immutable data structure that cannot be assigned to(c) No error: greetStrings is a mutable variable that can be assigned to(d) No error: Array is a mutable data structure that can be assigned to TI1220 - Introduction 72
  • 73. Exam Question (Week 2)What is the return type of makeRowSeq:def makeRowSeq(row: Int) = for (col <- 1 to 10) yield { val prod = (row * col).toString val padding = " " * (4 - prod.length) padding + prod }(a) String(b) Int(c) IndexedSeq[String](d) IndexedSeq[Int] TI1220 - Introduction 73
  • 74. PicturescopyrightsSlide 1: A Plumpish Proportion by SSG Robert Stewart some rights reservedSlide 3: McPhillips’ Map of the City of Winnipeg by Manitoba Historical Maps, some rights reservedSlide 19: Envelopes by benchilada, some rights reservedSlide 20: Report card by Carosaurus, some rights reservedSlide 30: Sun is Shining by el patojo, some rights reserved B:6.1 TI 1220 - Lecture 2: Functional Objects 74
  • 75. PicturescopyrightsSlide: Dinner at Roussillon (Martin Odersky) by Miles Sabin, some rights reservedSlide: Portrait: Alex Payne by Dave Fayram, some rights reservedSlide: “Plumbing Nightmare” by Natalie Wilkie, some rights reservedSlide: HIV: The Moleskine Summary by Niels OlsonSlide: remember to thank all the books you haven’t read over the past three years by Natalia Osiatynska, Some rights reservedSlide: Stupid Exam by Remi Carreiro, Some rights reservedSlide: Practice makes perfect by Simon Proberthttp://www.flickr.com/photos/garrettc/3747802654/ Bombe detail by Garret Coakley, Some rightsreserved B:6.1 TI 1220 - Lecture 2: Functional Objects 75