Top Banner
TI1220 2012-2013 Concepts of Programming Languages Eelco Visser / TU Delft Lecture 6: Polymorphism
67
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Ti1220 Lecture 7: Polymorphism

TI1220 2012-2013Concepts of Programming Languages

Eelco Visser / TU Delft

Lecture 6: Polymorphism

Page 2: Ti1220 Lecture 7: Polymorphism

Robin Milner is generally regarded as having made three major contributions to computer science. He developed LCF, one of the first tools for automated theorem proving. The language he developed for LCF, ML, was the first language with polymorphic type inference and type-safe exception handling. In a very different area, Milner also developed a theoretical framework for analyzing concurrent systems, the calculus of communicating systems (CCS), and its successor, the pi-calculus. At the time of his death, he was working on bigraphs, a formalism for ubiquitous computing subsuming CCS and the pi-calculus.[9]

http://en.wikipedia.org/wiki/Robin_Milner

Page 3: Ti1220 Lecture 7: Polymorphism

Outline

Control abstraction

Polymorphism

Lab & Exam

Page 4: Ti1220 Lecture 7: Polymorphism

Control Abstraction with Higher-Order Functions

Page 5: Ti1220 Lecture 7: Polymorphism

Higher-order functions

• reducing code duplication, simplifying client code

Currying

• partial function applications

Writing new control structures

• growing the language

By-name parameters

• lazy evaluation

Page 6: Ti1220 Lecture 7: Polymorphism

object FileMatcher { private def filesHere = (new java.io.File(".")).listFiles def filesEnding(query: String) = for(file <- filesHere; if file.getName.endsWith(query)) yield file}

Search for files that end in ...

Page 7: Ti1220 Lecture 7: Polymorphism

def filesEnding(query: String) = for(file <- filesHere; if file.getName.endsWith(query)) yield file

def filesContaining(query: String) = for(file <- filesHere;if file.getName.contains(query)) yield file

def filesRegex(query: String) = for(file <- filesHere;if file.getName.matches(query)) yield file

Search for files that match a query ...

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

Find the common pattern

Page 8: Ti1220 Lecture 7: Polymorphism

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

def filesEnding(query: String) = filesMatching(query, (x:String,y:String) => x.endsWith(y))def filesContaining(query: String) = filesMatching(query, _.contains(_))def filesRegex(query: String) = filesMatching(query, _.matches(_))

Using a higher-order function

Page 9: Ti1220 Lecture 7: Polymorphism

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(_))def filesRegex(query: String) = filesMatching(query, _.matches(_))

Using a higher-order function

Page 10: Ti1220 Lecture 7: Polymorphism

object FileMatcher { private def filesHere = (new java.io.File(".")).listFiles private def filesMatching(matcher: String => Boolean) = for (file <- filesHere; if matcher(file.getName)) yield file

def filesEnding(query: String) = filesMatching(_.endsWith(query)) def filesContaining(query: String) = filesMatching(_.contains(query)) def filesRegex(query: String) = filesMatching(_.matches(query))}

Using closures

Page 11: Ti1220 Lecture 7: Polymorphism

def containsNeg(nums: List[Int]): Boolean = { var exists = false for (num <- nums) if (num < 0) exists = true exists}

scala> containsNeg(List(1, 2, 3, 4))res3: Boolean = false

scala> containsNeg(List(1, 2, -3, 4))res5: Boolean = true

Using explicit iteration

def containsNeg(nums: List[Int]) = nums.exists(_ < 0)

Using higher-order iteration

Page 12: Ti1220 Lecture 7: Polymorphism

def containsOdd(nums: List[Int]): Boolean = { var exists = false for (num <- nums) if (num % 2 == 1) exists = true exists}

def containsOdd(nums: List[Int]) = nums.exists(_ % 2 == 1)

Explicit vs higher-order iteration

Page 13: Ti1220 Lecture 7: Polymorphism

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

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

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

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

scala> def first(x : Int) = (y : Int) => x + yfirst: (x: Int)(Int) => Int

scala> val second = first(1)second: (Int) => Int = <function1>

scala> second(2)res12: Int = 3

Currying

Page 14: Ti1220 Lecture 7: Polymorphism

scala> val onePlus = curriedSum(1)_onePlus: (Int) => Int = <function1>

scala> onePlus(2)res13: Int = 3

scala> val twoPlus = curriedSum(2)_twoPlus: (Int) => Int = <function1>

scala> twoPlus(2)res14: Int = 4

Currying

Page 15: Ti1220 Lecture 7: Polymorphism

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

scala> twice(_ + 1, 5)res15: Double = 7.0

scala> twice((x: Double) => x + 1, 5)res15: Double = 7.0

Making new control structures

Page 16: Ti1220 Lecture 7: Polymorphism

def withPrintWriter(file: File, op: PrintWriter => Unit) { val writer = new PrintWriter(file) try { op(writer) } finally { writer.close() }}

withPrintWriter( new File("date.txt"), writer => writer.println(new java.util.Date))

Loan Pattern: encapsulate allocation and de-allocation of resources

Page 17: Ti1220 Lecture 7: Polymorphism

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

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

Curly braces as function call

Page 18: Ti1220 Lecture 7: Polymorphism

def withPrintWriter(file: File)(op: PrintWriter => Unit) { val writer = new PrintWriter(file) try { op(writer) } finally { writer.close() }}

val file = new File("date.txt")withPrintWriter(file) { writer => writer.println(new java.util.Date)}

Loan pattern using curried higher-order functions

Page 19: Ti1220 Lecture 7: Polymorphism

var assertionsEnabled = truedef myAssert(predicate: () => Boolean) = if (assertionsEnabled && !predicate()) throw new AssertionError

myAssert(() => 5 > 3)

myAssert(5 > 3) // Won’t work, because missing () =>

How to defer evaluation?

Page 20: Ti1220 Lecture 7: Polymorphism

def boolAssert(predicate: Boolean) = if (assertionsEnabled && !predicate) throw new AssertionError

scala> boolAssert(5 > 3)

scala> assertionsEnabled = false assertionsEnabled: Boolean = false

scala> boolAssert(10 / 0 == 0)java.lang.ArithmeticException: / by zero at .<init>(<console>:8)

Function arguments are evaluated eagerly

Page 21: Ti1220 Lecture 7: Polymorphism

def byNameAssert(predicate: => Boolean) = if (assertionsEnabled && !predicate) throw new AssertionError scala> byNameAssert(5 > 3)

scala> byNameAssert(10 / 0 == 0)

By-name parameters are evaluated on demand

Page 22: Ti1220 Lecture 7: Polymorphism

Re-occurring patterns

• transform every element of a list

• verify property of all elements of a list

• extract elements satisfying some criterion

• combining elements of a list using some operator

Higher-order functions

• direct, reusable definitions of such patterns

Page 23: Ti1220 Lecture 7: Polymorphism

Higher-order functions

• reducing code duplication, simplifying client code

Currying

• partial function applications

Writing new control structures

• growing the language

By-name parameters

• lazy evaluation

Page 24: Ti1220 Lecture 7: Polymorphism

Polymorphic Type Systems

Page 25: Ti1220 Lecture 7: Polymorphism

Bool x, y;x && yx || y

!x

type

data type: a collection of data values and a set of predefined operations on those values

operations

Lecture 4

Page 26: Ti1220 Lecture 7: Polymorphism

type checking: the activity of ensuring that the operands of an operation are of compatible types.

A compatible type is one that either is legal for the operator or is allowed under language rules to be implicitly converted (coerced) to a legal type

type error: the application of an operator to an operand of an inappropriate type.

Type Compatible = Type Equallimits code reuse

Lecture 4

Page 27: Ti1220 Lecture 7: Polymorphism

Repeat pattern for each type

Monomorphic Functions

def map(xs: IntList, f: Int => Int): IntList = xs match { case Nil() => Nil() case Cons(y, ys) => Cons(f(y), map(ys, f))} def inc(xs: IntList) = map(xs, ((x:Int) => x + 1)) def square(xs: IntList) = map(xs, ((x:Int) => x * x))

Page 28: Ti1220 Lecture 7: Polymorphism

In computer science, polymorphism is a programming language feature that allows values of different data types to be handled using a uniform interface.

The concept of parametric polymorphism applies to both data types and functions.

A function that can evaluate to or be applied to values of different types is known as a polymorphic function.

A data type that can appear to be of a generalized type (e.g., a list with elements of arbitrary type) is designated polymorphic data type like the generalized type from which such specializations are made.

Page 29: Ti1220 Lecture 7: Polymorphism

Polymorphism

Inclusion polymorphism

Parametric polymorphism

Overloading

Page 30: Ti1220 Lecture 7: Polymorphism

Inclusion Polymorphism

Page 31: Ti1220 Lecture 7: Polymorphism

In object-oriented programming, subtype polymorphism or inclusion

polymorphism is a concept in type theory wherein a name may denote instances of many different classes as long as they are related by

some common super class. Inclusion polymorphism is generally supported through subtyping, i.e., objects of different types are

entirely substitutable for objects of another type (their base type(s)) and thus can be handled via

a common interface.

http://en.wikipedia.org/wiki/Polymorphism_(computer_science)

Page 32: Ti1220 Lecture 7: Polymorphism

Type T is a set of values with some operations.

A subtype of T is a subset of the values of type T, and therefore may be used in a context

where a value of type T is expected.

char,int subtype-of long

float subtype-of double

C:

Page 33: Ti1220 Lecture 7: Polymorphism

If S subtype-of T, then

Every value of S is also a value of T

A value in S can be used where a value of type T is expected

Operations of T can be applied to values in S (S inherits the operations)

Page 34: Ti1220 Lecture 7: Polymorphism

Substitutability is a principle in object-oriented programming. It states that, in a computer program, if

S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e., objects of type S

may be substituted for objects of type T) without altering any of the desirable properties of that program (correctness, task performed, etc.).

Liskov Substitution Principle

http://en.wikipedia.org/wiki/Liskov_substitution_principle

Page 35: Ti1220 Lecture 7: Polymorphism

Context:- e has type T1- var x: T2 = e- def f(x: T2) and f(e)

Is T1 compatible with T2?T1 is a subtype of T2: safe, by substitutabilityT1 is not a subtype of T2: requires run-time type check

Page 36: Ti1220 Lecture 7: Polymorphism

class Point { protected double x, y; public void draw() { /* ... */ }}

class Circle extends Point { private double r; public void draw() { /* ... */ }}

class Rectangle extends Point { private double w, h; public void draw() { /* ... */ }}

Point p;p = new Point(3.0, 4.0);p = new Circle(3.0, 4.0, 5.0);

TypePoint = Point(Double x Double) + Circle(Doube x Double x Double) + Rectangle(Double x Double x Double x Double)

Subtype and Inheritance in Java

Page 37: Ti1220 Lecture 7: Polymorphism

class Base { Integer x; public Base(Integer v) { x = v; } public void print() { System.out.println("Base: " + x); }}class Child extends Base { Integer y; public Child(Integer v1, Integer v2) { super(v1); y = v2; } public void print() { System.out.println("Child: (" + x + "," + y + ")"); }}

class BaseTest { public static void main(String[] args) { Base base1 = new Base(45); Base base2 = new Child(567, 245); base1.print(); base2.print(); }}

Dynamic Dispatch in Java

Page 38: Ti1220 Lecture 7: Polymorphism

Prototype Inheritancein JavaScript

Page 39: Ti1220 Lecture 7: Polymorphism

objects in JavaScript are dynamically composed without class blueprints

⇒dynamic structural subtyping

Page 41: Ti1220 Lecture 7: Polymorphism

var Duck = function(){ this.quack = function(){alert('Quaaaaaack!');}; this.feathers = function(){alert('The duck has white and gray feathers.');}; return this;}; var Person = function(){ this.quack = function(){alert('The person imitates a duck.');}; this.feathers = function(){alert('The person takes a feather from the ground and shows it.');}; this.name = function(){alert('John Smith');}; return this;}; var in_the_forest = function(duck){ duck.quack(); duck.feathers();}; var game = function(){ var donald = new Duck(); var john = new Person(); in_the_forest(donald); in_the_forest(john);}; game();

Duck typing in Java Script

http://en.wikipedia.org/wiki/Duck_typing#In_JavaScript

Page 42: Ti1220 Lecture 7: Polymorphism

How to organize code reuse?

Page 43: Ti1220 Lecture 7: Polymorphism

objects in JavaScript inherit from a prototype object

Page 44: Ti1220 Lecture 7: Polymorphism

var o1 = Object.create({x:1, y:2}); // o1 inherits properties x and y.

var o2 = Object.create(null); // o2 inherits no props or methods.

var o3 = Object.create(Object.prototype); // o3 is like {} or new Object().

Object.create()

Page 45: Ti1220 Lecture 7: Polymorphism

var p = {x:1}; // Define a prototype object.

var o = Object.create(p); // Create an object with that prototype.

p.isPrototypeOf(o) // => true: o inherits from p

Object.prototype.isPrototypeOf(p) // => true: p inherits from Object.prototype

The prototype Attribute

Page 46: Ti1220 Lecture 7: Polymorphism

var o = {} // o inherits object methods from Object.prototypeo.x = 1; // and has an own property x.var p = Object.create(o); // p inherits properties from o and Object.prototypep.y = 2; // and has an own property y.var q = Object.create(p); // q inherits properties from p, o, and Object.prototypeq.z = 3; // and has an own property z.var s = q.toString(); // toString is inherited from Object.prototypeq.x + q.y // => 3: x and y are inherited from o and p

Inheritance

Page 47: Ti1220 Lecture 7: Polymorphism

var unitcircle = { r:1 }; // An object to inherit from

var c = Object.create(unitcircle); // c inherits the property r

c.x = 1; c.y = 1; // c defines two properties of its own

c.r = 2; // c overrides its inherited property

unitcircle.r; // => 1: the prototype object is not affected

Inheritance

Page 48: Ti1220 Lecture 7: Polymorphism

function range(from, to) { var r = Object.create(range.methods); r.from = from; r.to = to; return r;}range.methods = { includes : function(x) { return this.from <= x && x <= this.to; }, foreach : function(f) { for ( var x = Math.ceil(this.from); x <= this.to; x++) f(x); }, toString : function() { return "(" + this.from + "..." + this.to + ")"; }};var r = range(1, 3); // Create a range objectr.includes(2); // => true: 2 is in the ranger.foreach(console.log); // Prints 1 2 3console.log(r); // Prints (1...3)

Classes and Prototypes

Page 49: Ti1220 Lecture 7: Polymorphism

function Range(from, to) { this.from = from; this.to = to;}Range.prototype = { includes : function(x) { return this.from <= x && x <= this.to; }, foreach : function(f) { for ( var x = Math.ceil(this.from); x <= this.to; x++) f(x); }, toString : function() { return "(" + this.from + "..." + this.to + ")"; }};var r = new Range(1, 3); // Create a range objectr.includes(2); // => true: 2 is in the ranger.foreach(console.log); // Prints 1 2 3console.log(r); // Prints (1...3)

Classes and Constructors

Page 50: Ti1220 Lecture 7: Polymorphism

Constructors and Class Identity

r instanceof Range // returns true if r inherits // from Range.prototype

Page 51: Ti1220 Lecture 7: Polymorphism

var F = function() {}; // This is a function object.var p = F.prototype; // This is the prototype object associated with it.var c = p.constructor; // This is the function associated with the prototype.c === F // => true: F.prototype.constructor==F for any functionvar o = new F(); // Create an object o of class Fo.constructor === F // => true: the constructor property specifies the class

Constructor Property

Page 52: Ti1220 Lecture 7: Polymorphism

function Range(from, to) { this.from = from; this.to = to;} Range.prototype.includes = function(x) { return this.from <= x && x <= this.to;};Range.prototype.foreach = function(f) { for ( var x = Math.ceil(this.from); x <= this.to; x++) f(x);};Range.prototype.toString = function() { return "(" + this.from + "..." + this.to + ")";};

Extend Prototype

Page 53: Ti1220 Lecture 7: Polymorphism

Parametric Polymorphism

Page 54: Ti1220 Lecture 7: Polymorphism

If all code is written without mention of any specific type and thus can be used

transparently with any number of new types, it is called parametric polymorphism.

http://en.wikipedia.org/wiki/Polymorphism_(computer_science)

Page 55: Ti1220 Lecture 7: Polymorphism

A mono-morphic (single-shaped) procedure can operate only on arguments of a fixed type.

A poly-morphic (many-shaped) procedure can operate uniformly on arguments of a whole family of types.

Parametric polymorphism is a type system in which we can write polymorphic procedures.

Page 56: Ti1220 Lecture 7: Polymorphism

def map[A,B](xs: List[A], f: A => B): List[B] = xs match { case List() => List() case y :: ys => f(y) :: map(ys, f)} val l = map(List(1, 2, 3), ((x: Int) => x + 1))

Polymorphic function: parameterized with types

A => B : type of functions from type A to type B

Page 57: Ti1220 Lecture 7: Polymorphism

Overloading

Page 58: Ti1220 Lecture 7: Polymorphism

If the function denotes different and potentially heterogeneous implementations depending on a limited

range of individually specified types and combination, it is called ad-hoc polymorphism. Ad-hoc polymorphism

is supported in many languages using function and method overloading.

http://en.wikipedia.org/wiki/Polymorphism_(computer_science)

Page 59: Ti1220 Lecture 7: Polymorphism

Method Overloading

scala> val c = new Rational(3,7)c: Rational = 3/7

scala> c * 2res1: Rational = 6/7

def *(that: Rational): Rational = new Rational(numer * that.numer, denom * that.denom)

def *(i: Int): Rational = new Rational(numer * i, denom)

In a method call, the compiler picks the version of an overloaded method that correctly matches the

types of the arguments.

Page 60: Ti1220 Lecture 7: Polymorphism

Lab & Exam

Page 61: Ti1220 Lecture 7: Polymorphism

Graded Assignment 1Algebraic datatypes in CDynamic dispatch in C

Important datesDeadline: April 2, 2013 23:59Extension: April 5, 2013 23:59

Submitting after extension date is not possibleMaximum penalty for submitting after deadline: 6 pointsMinimum grade needed: 4Grade: 70% unit tests, 30% check listsGrade for GAs: average of four assignments

Page 63: Ti1220 Lecture 7: Polymorphism

Material for exam

Slides from lectures

Tutorial exercises

Sebesta: Chapters 1-3, 5-8

Programming in Scala: Chapters 1, 4-9, 15-16

K&R C: Chapters 1-6

JavaScript Good Parts: Chapters 1-4

Page 64: Ti1220 Lecture 7: Polymorphism

Content of exam

20% multiple choice questions about concepts

40% Scala programming (functional programming)

20% C programming (structures and pointers)

20% JavaScript programming (objects and prototypes)

Page 65: Ti1220 Lecture 7: Polymorphism

http://department.st.ewi.tudelft.nl/weblab/assignment/850

Answers will be published when 80 students have completed the exam

Page 66: Ti1220 Lecture 7: Polymorphism

Registration for Exam is Required

http://department.st.ewi.tudelft.nl/weblab/assignment/759 → Your Submission

Page 67: Ti1220 Lecture 7: Polymorphism

Good Luck!