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
Implementing Polymorphism
Dynamic method dispatch
 C++ adds a v-table to each object
from a class having virtual methods

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
Possible solution: introduce a “version” of
the vector
Each time the vector is modified the version
is incremented
Enumerator compares the version of the
vector with the one at time of creation
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