CSC447
Concepts of Programming Languages
Parametric Polymorphism
Instructor: James Riely
Monomorphic Linked Lists (C)
-
Implement linked lists in C for each pointer type?
| typedef struct Node Node; |
| struct Node { |
| int *head; |
| Node *tail; |
| }; |
| |
| int *get_last (Node *xs) { |
| while (xs->tail != NULL) { |
| xs = xs->tail; |
| } |
| return xs->head; |
| } |
Generic Linked Lists (C)
| typedef struct Node Node; |
| struct Node { |
| void *head; |
| Node *tail; |
| }; |
| |
| void *get_last (Node *xs) { |
| while (xs->tail != NULL) { |
| xs = xs->tail; |
| } |
| return xs->head; |
| } |
Generic Linked Lists (C)
-
No static protection against casts from (void *)
| typedef struct Node Node; |
| struct Node { |
| void *head; |
| Node *tail; |
| }; |
| int main () { |
| int *p = (int *) malloc (sizeof(int)); |
| *p = 2123456789; |
| Node *xs = (Node *) malloc (sizeof(Node)); |
| xs->tail = NULL; |
| xs->head = p; |
| double *q = get_last(xs); |
| printf ("q=%f\n", *q); |
| } |
$ clang -m32 parametric-03.c && ./a.out
q=96621069057346178268049192388430659584.000000
Monomorphic Lists (Java)
-
Implement linked lists in Java for each reference type?
| static class Node { |
| Integer head; |
| Node tail; |
| } |
| |
| static Integer getLast (Node xs) { |
| while (xs.tail != null) { |
| xs = xs.tail; |
| } |
| return xs.head; |
| } |
Generic Linked Lists (Java)
-
Generic list using subtype polymorphism
| static class Node { |
| Object head; |
| Node tail; |
| } |
| |
| static Object getLast (Node xs) { |
| while (xs.tail != null) { |
| xs = xs.tail; |
| } |
| return xs.head; |
| } |
Subtype polymorphism
-
ClassCastException
better than unsafe access
| static class Node { |
| Object head; |
| Node tail; |
| } |
| public static void main (String[] args) { |
| Integer p = Integer.valueOf(2123456789); |
| Node xs = new Node(); |
| xs.tail = null; |
| xs.head = p; |
| Double q = (Double) getLast(xs); |
| System.out.printf ("d=%f\n", q); |
| } |
$ javac Parametric2.java
$ java Parametric2
java.lang.ClassCastException: Integer cannot be cast to Double
at Parametric.main(Parametric2.java:10)
Generic Linked Lists (Java)
-
Generic list using parametric polymorphism
| static Node<X> { |
| X head; |
| Node<X> tail; |
| } |
| |
| static <X> X getLast (Node<X> xs) { |
| while (xs.tail != null) { |
| xs = xs.tail; |
| } |
| return xs.head; |
| } |
Parametric Polymorphism
-
Compiler errors better than runtime exceptions
| static class Node<X> { |
| X head; |
| Node<X> tail; |
| } |
| public static void main (String[] args) { |
| Integer p = Integer.valueOf(2123456789); |
| Node<Integer> xs = new Node<>(); |
| xs.tail = null; |
| xs.head = p; |
| Double q = (Double) getLast(xs); |
| System.out.printf ("d=%f\n", q); |
| } |
$ javac Parametric1.java
error: incompatible types: Integer cannot be converted to Double
Double q = (Double) getLast(xs); // compiler error
^
Java type parameter erasure
-
Java type parameters not stored at runtime
| static class ArrayList<X> { |
| X[] a; |
| |
| ArrayList(int n) { |
| a = new X[n]; |
| } |
| void put (int i, X item) { a[i] = item; } |
| X get (int i) { return a[i]; } |
| } |
$ javac Parametric3.java
error: generic array creation
a = new X[n];
^
Java type parameter erasure
-
Cast is not checked at runtime
| static class ArrayList<X> { |
| X[] a; |
| |
| ArrayList(int n) { |
| a = (X[]) new Object[n]; |
| } |
| void put (int i, X item) { a[i] = item; } |
| X get (int i) { return a[i]; } |
| } |
$ javac -Xlint:unchecked Parametric4.java
warning: [unchecked] unchecked cast
a = (X[]) new Object[n];
^
Java type parameter erasure
-
Okay to ignore, since array is empty
| static class ArrayList<X> { |
| X[] a; |
| @SuppressWarnings("unchecked") |
| ArrayList(int n) { |
| a = (X[]) new Object[n]; |
| } |
| void put (int i, X item) { a[i] = item; } |
| X get (int i) { return a[i]; } |
| } |
$ javac -Xlint:unchecked Parametric4.java
Java type parameter erasure
| ArrayList<String> ss = new ArrayList<>(10); |
| ArrayList os = ss; |
| os.put (1, 2123456789); |
| String s = ss.get (1); |
$ javac Parametric6.java
Note: Parametric6.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
$ java Parametric6
ClassCastException: Integer cannot be cast to class String
at Parametric.main(Parametric6.java:4)
Arrays checked when assigned
-
Java stores types with arrays
| String[] ss = new String[10]; |
| Object[] os = ss; |
| os[1] = 2123456789; |
| String s = ss[1]; |
$ javac Parametric7.java
$ java Parametric7
ArrayStoreException: Integer
at Parametric.main(Parametric7.java:3)
Parametric Polymorphism
-
In Java, C#, Ada, Haskell, Scala, Rust, etc
-
First developed in ML (1970s)
-
Modern descendants: F#, oCaml, Standard ML
-
Strong connection to mathematical logic
-
Leading to Agda, Coq, etc
-
C++ templates are different
-
Template itself has no executable form:
List<T>
-
Executable generated for each instantiation:
List<int>
, List<string>
CSC447 Concepts of Programming Languages Parametric Polymorphism Instructor: James Riely