Top Banner
Parametric Polymorphism Antonio Cisternino
38

Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Dec 19, 2015

Download

Documents

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: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Parametric Polymorphism

Antonio Cisternino

Page 2: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Parametric Polymorphism

C++ templates implement a form of parametric polymorphism

PP is implemented in many flavors and many languages: Eiffel, Mercury, Haskell, ADA, ML, C++…

Improve the expressivity of a language May improve the performance of

programs It is a form of Universal polymorphism

Page 3: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

C++ templates and macros

Macros are dealt by the preprocessor C++ templates are implemented on the syntax tree The instantiation strategy is lazy The following class compiles unless the method foo

is used:template <class T>class Foo { T x; int foo() { return x + 2; }};

Foo<char*> f;f.x = “”;f.foo();

Page 4: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

A more semantic approach

Parametric polymorphism has been introduced also in Java and C# Java Generics and Generic C# for .NET

In both cases the compiler is able to check parametric classes just looking at their definition

Parametric types are more than macros on AST

Syntax for generics is similar in both JG and C#

Page 5: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Generics in a Nutshell

Type parameterization for classes, interfaces, and methods e.g.

class Set<T> { ... } // parameterized classclass Dict<K,D> { ... } // two-parameter classinterface IComparable<T> { ... } // parameterized interfacestruct Pair<A,B> { ... } // parameterized struct (“value class”) T[] Slice<T>(T[] arr, int start, int count) // generic method

Very few restrictions on usage: Type instantiations can be primitive (only C#) or class e.g.

Set<int> Dict<string,List<float>> Pair<DateTime, MyClass> Generic methods of all kinds (static, instance, virtual) Inheritance through instantiated types e.g.

class Set<T> : IEnumerable<T>class FastIntSet : Set<int> Virtual methods

only in GC#!

In GJ is<T> T[] Slice(…)

Page 6: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

C#

JG

C++

Generic methods are similar to template methods in C++ As in C++ JG tries to infer the type parameters from the

method invocation C# requires specifying the type arguments Example:

template <class T> T sqr(T x) { return x*x; }std::cout << sqr(2.0) << std::endl;class F { <T> static void sort(T[] a) {…} }String[] s; F.sort(s);class F { static void sort<T>(T[] a) {…} }string[] s; F.sort<string>(s);

More on generic methods

Page 7: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Generic Stack

class Stack<T> { private T[] items; private int nitems; Stack<T> { nitems = 0; items = new T[] (50); } T Pop() { if (nitems == 0) throw Empty(); return items[--nitems]; } bool IsEmpty() { return (nitems == 0); } void Push(T item){ if (items.Length == nitems) { T[] temp = items; items = new T[nitems*2]; Array.Copy(temp, items, nitems); }

items[nitems++] = item;}

}

How does the compiler

check the definition?

Page 8: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Tip C++ requires a space in nested parameter types: vector<vector<int> > to avoid

ambiguity with operator >> GJ (and C#) fixed the problem with the following grammar:

ReferenceType ::= ClassOrInterfaceType | ArrayType | TypeVariableClassOrInterfaceType ::= Name | Name < ReferenceTypeList1ReferenceTypeList1 ::= ReferenceType1 | ReferenceTypeList , ReferenceType1ReferenceType1 ::= ReferenceType > | Name < ReferenceTypeList2ReferenceTypeList2 ::= ReferenceType2 | ReferenceTypeList , ReferenceType2ReferenceType2 ::= ReferenceType >> | Name < ReferenceTypeList3ReferenceTypeList3 ::= ReferenceType3 | ReferenceTypeList , ReferenceType3ReferenceType3 ::= ReferenceType >>>TypeParameters ::= < TypeParameterList1TypeParameterList1 ::= TypeParameter1 | TypeParameterList , TypeParameter1TypeParameter1 ::= TypeParameter > | TypeVariable extends ReferenceType2 |

TypeVariable implements ReferenceType2

Page 9: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

The semantic problem

The C++ compiler cannot make assumptions about type parameters

The only way to type-check a C++ class is to wait for argument specification (instantiation): only then it is possible to check operations used (i.e. comp method in sorting)

From the standpoint of the C++ compiler semantic module all types are not parametric

Page 10: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Checking class definition

To be able to type-check a parametric class just looking at its definition we introduce the notion of bound

As in method arguments have a type, type arguments are bound to other types

The compiler will allow to use values of such types as if upcasted to the bound

Example: class Vector<T : Sortable> Elements of the vector should implement (or

inherit from) Sortable

Page 11: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Example

interface Sortable<T> { int compareTo(T a);}class Vector<T : Sortable<T>> { T[] v; int sz; Vector() { sz = 0; v = new T[15]; } void addElement(T e) {…} void sort() { … if (v[i].compareTo(v[j]) > 0) … }}

Compiler can type-check this because v contains values that

implement Sortable<T>

Not possible in Java, because Sortable is an

interface and type T is lost.

Page 12: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Pros and Cons

A parameterized type is checked also if no instantiation is present

Assumptions on type parameters are always explicit (if no bound is specified Object is assumed)

Is it possible to made assumptions beyond bound? Yes, you can always cheat by upcasting to Object and then to

whatever you want:class Foo<T : Button> { void foo(T b) { String s = (String)(Object)b; }}

Still the assumption made by the programmer is explicit

Page 13: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Implementation

Alternative implementations of parametric polymorphism:

C++ generates Abstract Syntax Tree for method and classes

GJ implements generic types at compile time: the JVM is not aware of parametric types

C# assumes that CLR is aware of parametric types: the IL has been extended with generic instructions to handle with type parameters

Page 14: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Java Generics strategy

JG is an extension of Java The compiler verifies that generic types

are used correctly Type parameters are dropped and the

bound is used instead; downcasts are inserted in the right places

The output is a normal class file unaware of parametric polymorphism

Page 15: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Example

class Vector<T> { T[] v; int sz; Vector() { v = new T[15]; sz = 0; } <U implements Comparer<T>> void sort(U c) { … c.compare(v[i], v[j]); … }}…Vector<Button> v;v.addElement(new Button());Button b = v.elementAt(0);

class Vector { Object[] v; int sz; Vector() { v = new Object[15]; sz = 0; } void sort(Comparer c) { … c.compare(v[i], v[j]); … }}…Vector v;v.addElement(new Button());Button b =

(Button)b.elementAt(0);

Page 16: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Wildcard

class Pair<X,Y>  {    X first;   Y second;

}public String pairString(Pair<?, ?> p) {

return p.first + “, “ + p.second;}

Page 17: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Expressivity vs. efficiency

JG doesn’t improve execution speed; though it helps to express genericity better than inheritance

There is a main limit in JG expressivity: at runtime exact type information is lost

All instantiations of a generic type collapse to the same class

Consequences are no virtual generic methods and pathological situations

Benefit: Java classes could be seen as generic types! Reuse of the large existing codebase

JG isn’t the only implementation of generics for Java

Page 18: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Generics and JavaJG/PizzaBracha, Odersky,Stoutamire, Wadler

NextGen Cartwright, Steele

PolyJ Bank, Liskov, Myers

Agesen, Freund, Mitchell

Generic CLRKennedy,Syme

Parameterized types

+ bounds

+ bounds

+

constraints

+ bounds

+ bounds

Polymorphic methods Type checking at point of definition Non-reference instantiations Exact run-time types ? Polymorphic virtual methods Type parameter variance

System

Feature

Page 19: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Problem with JG

Stack<String> s = new Stack<String>();

s.push("Hello");

Stack<Object> o = s;

Stack<Button> b = (Stack<Button>)o;

// Class cast exception

Button mb = b.pop(); Cast authorized: both Stack<String> and Stack<Button> map to class Stack

Page 20: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Generic C# Strategy: GCLR

Kennedy and Syme have extended CLR to support parametric types (the same proposal has been made for PolyJ by Cartwright and Steele)

In IL placeholders are used to indicate type arguments (!0, !1, …)

The verifier, JIT and loader have been changed When the program needs an instantiation of a

generic type the loader generates the appropriate type

The JIT can share implementation of reference instantiations (Stack<String> has essentially the same code of Stack<Object>)

Page 21: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Generic C# compiler

GC# compiler implements a JG like notation for parametric types

Bounds are the same as in JG NO type-inference on generic methods: the

type must be specified in the call The compiler relies on GCLR to generate the

code Exact runtime types are granted by CLR so

virtual generic methods are allowed All type constructors can be parameterized:

struct, classes, interfaces and delegates.

Page 22: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Example

using System;namespace n { public class Foo<T> { T[] v; Foo() { v = new T[15]; } public static void Main(string[] args) { Foo<string> f = new Foo<string>(); f.v[0] = "Hello"; string h = f.v[0]; Console.Write(h); } }}

.field private !0[] v

.method private hidebysig specialname

rtspecialnameinstance void .ctor() cil

managed { .maxstack 2 ldarg.0 call instance void

[mscorlib]System.Object::.ctor()

ldarg.0 ldc.i4.s 15 newarr !0 stfld !0[] class n.Foo<!

0>::v ret} // end of method Foo::.ctor

Page 23: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Performance

The idea of extending CLR with generic types seems good; but how about performance?

Although the instantiation is performed at load time the overhead is minimal

Moreover code sharing reduces instantiations, improving execution speed

A technique based on dictionaries is employed to keep track of already instantiated types

Page 24: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Expressive power of Generics

System F is a typed -calculus with polymorphic types

While Turing-equivalence is a trivial property of programming languages; for a type-system being equivalent to System F it is not

Polymorphic languages such as ML and Haskell cannot fully express System F (both languages have been extended to fill the gap)

System F can be transposed into C# http://www.cs.kun.nl/~erikpoll/ftfjp/2002/KennedySyme.pdf

Page 25: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Reminder: substitutivity

Sub-Typing/Sub-Classing defines the class relation “B is a sub-type of A”, marked B <: A.

According to the substitution principle, if B <: A, then an instance of B can substitute an instance of A.

Therefore, it is legal to assign an instance b of B to a reference of AA a = b

Page 26: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Generics and Subtyping

Does the rules for sub-types and assignment works for generics?If B <: A, then G<B> <: G<A>?

List<String> ls = new List<String>();List<Object> lo = ls;// Since String <: Object, so far so good.lo.add(new Object());String s = ls.get(0); // Error!

The rule B <: A G<B> <: G<A> defies the principle of substitution!

Counter example

Page 27: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Other example

class B extends A { … }class G<E> { public E e;}G<B> gb = new G<B>();G<A> ga = gb;ga.e = new A();B b = gb.e; // Error!

Given B <: A, and assuming G<B> <: G<A>, then:G<A> ga = gb;would be legal.Actually, type is erased.

Page 28: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Bounded Wildcard

A wildcard does not allow doing much

To provide operations with wildcard types, one can specify bounds:

Upper Bound The ancestor of unknown:G<? extends X>

Lower Bound The descendant of unknown:G<? super Y>

Page 29: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Bounded Wildcards Subtyping Rules

For any B such that B <: A: G<B> <: G<? extends A> G<A> <: G<? super B>

Page 30: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Bounded Wildcards - Example

G<A> ga = new G<A>();

G<B> gb = new G<B>();

G<? extends A> gea = gb;

// Can read from

A a = gea.e;

G<? super B> gsb = ga;

// Can write to

gsb.e = new B();

G<B> <: G<? extends A>

hence legal

G<A> <: G<? super B>

hence legal

Page 31: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Generics and Polymorphism

class Shape { void draw() {…} }class Circle { void draw() {…} }class Rectangle { void draw() {…} }

public void drawAll(Collection<? extends Shape> shapes) { for (Shape s: shapes) s.draw();}

Collection<Shape> will not work. Why?

Page 32: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Lower Bound Example

interface sink<T> { flush(T t);}

public <T> T flushAll(Collection<T> col, Sink<T> sink)

{ T last; for (T t: col) { last = t; sink.flush(t);} return last;}

Page 33: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Lower Bound Example (2)

Sink<Object> s;

Collection<String> cs;

String str = flushAll(cs, s); // Error!

Page 34: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Lower Bound Example (3)

public <T> T flushAll(Collection<T> col, Sink<T> sink) { … }

…String str = flushAll(cs, s); // Error!

T is now solvable as Object, but it is not the correct type: should be String

Page 35: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Lower Bound Example (4)

public <T> T flushAll(Collection<T> col, Sink<? Super T> sink) { … }

String str = flushAll(cs, s); // OK!

Page 36: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Combining generics and Combining generics and inheritanceinheritance The inheritance relation must be extended

with a new subtyping rule:

Can now cast up and down to Object safely Note: types must be substituted because the

super-class can be parametric

Givenclass C<T1,...,Tn> extends B

we have C<t1,...,tn> <: B[t1/T1, ..., tn/Tn]

Page 37: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Manipulating types

Grouping values into types has helped us to build better compilers

Could we do the same with types? Types can be grouped by means of

inheritance which represents the union of type sets

Parametric types combined with inheritance allow expressing function on types:class Stack<T:object> : Container

Function name Function arguments Result type

Page 38: Parametric Polymorphism Antonio Cisternino. Parametric Polymorphism C++ templates implement a form of parametric polymorphism PP is implemented in many.

Example: generic containers

class Row<T : Control> : Control{ /* row of graphic controls *> }class Column<T : Control> : Control{ /* column of graphic controls */ }class Table<T : Control> : Row<Column<T>>{ /* Table of graphic controls */ }…// It generates the keypad of a calculatorTable<Button> t = new Table<Button>(3, 3);for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) t[i, j].Text = (i * 3 + j + 1).ToString();