Polymorphism

Download Report

Transcript Polymorphism

Polymorphism
Giuseppe Attardi
Antonio Cisternino
Generic programming




Code reuse is clearly a good idea
Often an algorithm can be applicable to many objects
Goal is to avoid rewriting as much as possible
Types introduce great benefits but also may limit code
reuse:
int sqr(int i, int j) { return i*j; }
double sqr(double i, double j) {return i*j; }


The notion of sqr is unique but we must define it twice
because of types
Languages offer mechanisms to address this problem
Polymorphism


The ability of associate more than one meaning
to a name in a program
We have already seen two kinds of
polymorphism:
 Subtype/inclusion
(inheritance)
 Overloading


Polymorphism is the fundamental mechanism for
generic programming
There are other kinds of polymorphism
Classification of Polymorphism
Parametric
Universal
Inclusion
Polymorphism
Overloading
Ad hoc
Coercion
Universal vs. ad hoc polymorphism




With overloading an implementation for each
signature is required
We provide ad hoc solutions for different objects
Inheritance instead allows defining algorithms
that operate on all classes of objects that inherit
from a given class
In this case a single (universal) solution applies
to different objects
Containers

Example: Java Vector
Vector v = new Vector();
v.addElement("Pippo");
v.addElement(new Integer(2));

Signature of addElement:
void addElement(Object x);

The argument is of type Object because the
container may contain any type of object
Problem with containers


Inserting an object in a vector we loose type
information
In our example we implicitly upcast from String
to Object:
v.addElement("Pippo");

Extracting the second element with the wrong
cast produces a runtime error:
Integer i = (Integer)v.elementAt(0);
Weakest constraint programming

Where do we assume something about objects that we manipulate?
class Vector {
Object[] v;
int size;
public Vector() {
v = new Object[15];
size = 0;
}
public addElement(Object e) {
if (size == v.length) {
Object[] w = new Object[](2 * size);
w.copy(v, 0, size);
v = w;
}
v[size++] = e;
}}

We assume only assignment operations and arrays: operation
available on all objects
Can we sort our vector?




How to add a method for sorting a vector?
We do not have enough information on our objects: no
comparison operation is available
Our vector is too generic!
Two solutions:

accept only objects that implement an interface (i.e.
IComparable) that exposes a method to compare objects
public void addElement(IComparable e) {…}

Pass a functional object: an object which implements an
interface for comparing Object instances (i.e. IComparator)
public void Sort(IComparator c) {…}
interface IComparator {
int compare(Object x, Object y); }
Abstract as much as possible!



To express generic code with subtype
polymorphism we should abstract the essence of
the operations required on the objects we want
to manipulate
Risk is over-abstraction: once defined our vector
we can’t easily add a sort method
Another issue: inheritance relies on explicit
annotation of our types and changes are hard to
perform
Iterating over a collection




A common programming pattern is to enumerate the
elements of a collection
It doesn’t really matter how the collection is organized
We can implement a class per collection type whose
objects enumerates the elements.
Interface
Example:
Enumeration elements() { return ???; }
void printCollection(Enumeration e) {
while (e = hasMoreElements()) {
Object o = e.nextElement();
System.out.println(o);
}}
Question

Which class implements method elements?
 Class Vector
 Use overloading and singleton
class Enumeration {
static Enumeration getEnumeration(Vector v){
return v.elements();
}
// Other collections’ enumerators
}

Thus we can add enumerators to existing
collections
Enumerator for Vector
class VectorEnum implements Enumeration {
int idx;
Vector v;
bool hasMoreElements() { idx < v.size(); }
Object nextElement() {
return v.elementAt(idx++);
}
VectorEnum(Vector v) {
idx = 0;
this.v = v; // why it is not copied?
}
}
Is the enumerator up to date?






To ensure that the enumerator is consistent the vector
should be copied into the enumerator
This isn’t reasonable: memory wasted and we iterate on
a different vector!
There is no way to ensure that the enumerator is
consistent with the vector
Nonetheless it is possible to do something: we introduce
a “version” of the vector
Each time the vector is modified the version is
incremented
The enumerator compares the version of the vector with
the one of the vector when it has been created
Event handling in GUI




Before Java 1.1 OO GUI frameworks were
based on sub-typing
GUI can be easily described using generic
programming: buttons are a subtype of control
which is a special window
Containers of graphical widgets operates on
controls, irrespective of their types
Event dispatching and handling is dealt by
virtual methods
 hence
by default is delegated to the super-type
Java AWT Event Model
class Component {
int x, y;
bool handleEvent(Event e);
}
class Button extends Component {
String text;
bool handleEvent(Event e) { }
…
}
class Window extends Component { … }
class Frame extends Window { … }
Event handling
class MyButton extends Button {
boolean handleEvent(Event e) {
switch (e.type) {
case Event.MOUSE_UP: …
return true; // Event handled!
}
default:
return super.handleEvent(e);
}}
Limits of AWT Event Model
Generic programming in this case is quite
elegant but inefficient
 Propagation of events to a number of
handlers, mostly useless
 Proliferation of classes: one for each
object with different behavior

Alternative





Event Delegation model
Observer Pattern (aka publish/subscribe)
Observable has set of registered observers
Observable notifies its observers when its state
changes
Handling performed by objects that provide a
Listener interface (aka callback, delegate)
Java JDBC
Java DataBase Connectivity is a
specification from Sun for accessing
databases in Java
 Interesting example of generic
programming
 It implements a driver architecture
exploiting the mechanisms of JVM

Overall architecture




The java.sql package exposes only interfaces
The only class is DriverManager
Using the class constructor a driver register itself
with the DriverManager
The programmer performs the following steps:
 Load the database driver (a Java class)
 Create a connection to a database (using
DriverManager)
 Obtain a Statement and execute the query
 Enumerate the rows using a ResultSet
JDBC example
Class.forName("…"); // Load the driver
Connection c =
DriverManager.getConnection("…");
Statement s = c.createStatement();
ResultSet r = s.executeQuery("select …");
while (r.hasNext()) {
// Value of second column as String
String s = r.getString(2);
}
Question




Statement is Class or Interface?
Connection, Statement are Interfaces
Through the DriverManager the program obtains
an object of unknown type which implements the
Connection interface
The same applies to all the other interfaces:
through the connection an object implementing
Statement is obtained, and so on and so forth