Generic Subroutines

Download Report

Transcript Generic Subroutines

Generic Subroutines and
Exceptions
CS351 – Programming Paradigms
Motivations



Subroutines provide a natural way of abstracting data operations.
With large programs containing many methods it is possible that
subroutines will be needed to perform similar operations on many
different types.
Consider some code from any language:
String add (String a, String b)
return a + b;
int add ( int a, int b )
return a + b;
double add ( double a, double b)
return a + b;


What is wrong with this code?
Nothing!
Motivations






The code is correct but the repetitious operations must be defined
statically many times over.
We need a form of parametric parameterisation i.e the subroutine
should only be written once and be capable of accepting any
arguments.
This idea is known as generic programming.
In Java version 5, generic programming has been added.
In C++, generics are known as templates.
Other languages that feature generics are Ada, Modula-3 and C#.
Generics




Generics are especially helpful for creating container
classes.
Container classes are data abstractions that hold a
collection of objects.
The operation of the container class is independent of
the type of object stored.
Some examples of container classes include….




Stack
Queue
Set
Heap…
Generic Subroutines



Generic subroutines are needed in generic classes.
They allow a method to be parameterised by a single type.
Hence our earlier example becomes vastly simplified:
public T <T> add ( T a, T b)
return a + b;


This code is now identical to the first slide except we now have a
generic type T passed as a parameter to the add method.
Hence we can now call the code:
int c = add( 5 , 7 );
double d = add ( 4.5, 6.9 );
String concat = add( “gen” , “erics” );
Implementing Generics





In C++, they are a static mechanism.
All of the work required to use multiple instances of the generic
code is handled by the compiler.
The compiler creates a separate copy of the code for every
instance.
In Java, all instances of the generic code will shae that same
code at run-time.
If we call some generic parameter, T in Java, this behaves
identically to java.lang.Object except that we do not have to use
casts.
Generics in C++



The syntax is similar but the behaviour is more flexiable than
Java.
However it is easier to make mistakes with C++.
A generic add method in C++:
template<typename T> T add (T a, T b)
{
return a+b;
}


To call the method
add(5,6);
add(5.6 , 7.8);
The compiler figures out all of the hard work.
Generics in Java


``Old’’ Java:
A Vector of ints:
/* Adding to a Vector */
Vector v = new Vector();
for ( int i = 0; i < 10; i++ )
v.add(new Integer(i));
/* Removing from a Vector */
for ( int z = 0; z<v.size(); z++ )
int a = ((Integer)v.elementAt(z)).intValue();

Looks very messy especially, the cast involved when reading from the
Vector
 With generics:
/* Adding to a Vector */
/* Removing from Vector */
Vector<Integer> v = new Vector<Integer> ();
for (int i = 0; i < 10 ; i++)
v.add(i);
for (int a : v)
Java Generics : Erasure



Generics in Java are defined in terms of type erasure.
This means that every generic type parameter is replaced by
java.lang.Object and casts back to concrete types are
automatically inserted into the code by the compiler.
E.g.
class choice <T>
{ public boolean best ( T a , T b ) {} }
Is replaced by:
class choice
{ public boolean best ( Object a, Object b ) {} }

This is done to provide backwards compatibility with older non
generic Java code.
Java Generics

Recall the C++ example:
template<typename T> T add (T a, T b)
{
return a+b;
}

This allows any number ( int, float, short, double etc ) to be added
together.
 How can we achieve this is Java?
public <T> T add ( T a, T b )
{
return a+b;
}

Is this correct?
Java Generics

Lets perform the type erasure:
public Object add ( Object a, Object b )
{
return a+b;
}



Does this compile?
No!, because the + operator is not applicable to Object.
We must modify the code to make it typesafe so it can compile:
Java Generics
public <T extends Number> T add ( T a, T b )
{
return a+b;
}





We have to impose a higher bound on the type passed to the
generic method.
In this case we are saying that the type passed in will be a
subclass of java.lang.Number
Will the code compile now?
Nope!
We still have to make sure that it is typesafe.
Java Generics
public <T extends Number> T add ( T a, T b )
{
if ( T instanceof Integer )
return a.intValue() + b.intValue();
if ( T instanceof Double )
return a.doubleValue() + b.doubleValue();
return null;
}
public static void main( String args [] )
{
int a = add (5 , 6);
double b = add ( 7.9, 11.3 );
}

We are passing ints and doubles to add but the add method takes
Integers and Doubles, how is this?