Generic Trouble

S

Stefan Ram

I have defined a signature in an interface:

void addrac
( java.lang.Comparable< ? >container,
int position );

. I implemented this as follows in a class:

public void addrac
( final java.lang.Comparable< ? >container,
final int position )...

. This worked fine, until I needed to refer to the type »?«
within the body of the method. I tried to give it a name:

public< T >void addrac
( final java.lang.Comparable< T >container,
final int position )...

. But now Java tells me that this does *not* override the
method of the interface.

One step back in time: Actually, I started from this interface:

void addrac
( java.lang.Comparable container,
int position );

I inserted the »< ? >« only to get rid of a »rawtype« warning.

So what would be a good way to get rid of such »rawtype«
warnings, but also allow implementations to refer to the
type name in their body, when they need this? (Or how can
I get such a reference while still implementing the
signature of the interface?)
 
A

Arne Vajhøj

I have defined a signature in an interface:

void addrac
( java.lang.Comparable< ?>container,
int position );

. I implemented this as follows in a class:

public void addrac
( final java.lang.Comparable< ?>container,
final int position )...

. This worked fine, until I needed to refer to the type »?«
within the body of the method. I tried to give it a name:

public< T>void addrac
( final java.lang.Comparable< T>container,
final int position )...

. But now Java tells me that this does *not* override the
method of the interface.

One step back in time: Actually, I started from this interface:

void addrac
( java.lang.Comparable container,
int position );

I inserted the »< ?>« only to get rid of a »rawtype« warning.

So what would be a good way to get rid of such »rawtype«
warnings, but also allow implementations to refer to the
type name in their body, when they need this? (Or how can
I get such a reference while still implementing the
signature of the interface?)

Why not use <T> in the interface?

Arne
 
S

Stefan Ram

Arne Vajhøj said:
Why not use <T> in the interface?

If this is the recommended way to deal with a »rawtype«
warning, when one does not want to restrict the type
parameter to anything more special than »java.lang.Object«,
ok, I will do it.

I just had read advice before to use »< ? >« in such cases,
so I already have edited this into dozens of places. Ok,
so now I may go back and change it to »< T >«. I just want
a general and final solution, so that I will not have to
change this even more often.
 
A

Andreas Leitgeb

First of all, the generic class will *not* know the actual
type used. At most you can enforce it to be a subclass or
superclasses of some given class.

So let's assume that in your method you're going to deal with
type Number (which subclasses Object and is subclassed e.g. by
Integer):

Now, it depends on what you want to do with the Collection that
you're going to pass to that method:

- access elements *FROM* it:
use <T extends Number>, as that will allow
Collection<Number> but also Collection<Integer>
instances to be used.
- add (or overwrite) elements *TO* it:
use <T super Number>, as it is perfectly legal to write
objects that are known to be at least Numbers either to
a Collection<Object> as well as to a Collection<Number>
- do both of these above:
use Collection<Number>. Nothing else would allow for both
reading and writing Numbers.

And now, I guess, someone will come up and correct me in all those
points, where I decided to keep it simple to the point of omission
of some accuracy.
 
L

Lew

First of all, the generic class will *not* know the actual
type used. At most you can enforce it to be a subclass or
superclasses of some given class.

So let's assume that in your method you're going to deal with
type Number (which subclasses Object and is subclassed e.g. by
Integer):

Now, it depends on what you want to do with the Collection that
you're going to pass to that method:

- access elements *FROM* it:
use<T extends Number>, as that will allow
Collection<Number> but also Collection<Integer>
instances to be used.
- add (or overwrite) elements *TO* it:
use<T super Number>, as it is perfectly legal to write
objects that are known to be at least Numbers either to
a Collection<Object> as well as to a Collection<Number>
- do both of these above:
use Collection<Number>. Nothing else would allow for both
reading and writing Numbers.

And now, I guess, someone will come up and correct me in all those
points, where I decided to keep it simple to the point of omission
of some accuracy.

Looks correct from here.

Another point is that the <?> dodge works well for parameters to methods, but
not so well for returns from methods or member variable types.

The symptom the OP describes is a manifestation of incomplete type analysis.

The attempt to use a simplistic rule of thumb, like "always avoid raw types
with <?>", leads to such incomplete analysis. Unfortunately, to analyze types
down to where generics stop whing is to analyze them down to where you have
delineated all the type constraints completely. This is hard, especially when
you haven't yet gotten used to type analysis and type assertions, but it gets
a little better once you make the cognitive shift.

Don't think of generics as a way to eliminate warnings. If that's all you
need, just use raw types and '@SuppressWarnings("unchecked")'. Who needs all
that high-falutin' type safety anyway?

If you do need type safety, the good news is that a complete type analysis
reflects quite neatly as generics assertions in your Java code, and you will
have locked the door against all kinds of sneaky and
hard-to-diagnose-at-runtime bugs. I assess that the difficulty of generics is
precisely the difficulty of a complete type analysis. Thank goodness the
source records and the compiler enforces the results of that analysis.
 
J

John B. Matthews

Andreas Leitgeb said:
First of all, the generic class will *not* know the actual
type used. At most you can enforce it to be a subclass or
superclasses of some given class.

So let's assume that in your method you're going to deal with
type Number (which subclasses Object and is subclassed e.g. by
Integer):

Now, it depends on what you want to do with the Collection that
you're going to pass to that method:

- access elements *FROM* it:
use <T extends Number>, as that will allow
Collection<Number> but also Collection<Integer>
instances to be used.
- add (or overwrite) elements *TO* it:
use <T super Number>, as it is perfectly legal to write
objects that are known to be at least Numbers either to
a Collection<Object> as well as to a Collection<Number>
- do both of these above:
use Collection<Number>. Nothing else would allow for both
reading and writing Numbers.

And now, I guess, someone will come up and correct me in all those
points, where I decided to keep it simple to the point of omission
of some accuracy.

This is an informative explication of Joshua Bloch's maxim, PECS, an
acronym for producer-extends, consumer-super.

For reference, Effective Java Second Edition, Chapter 5, Item 28, Page 3
<http://java.sun.com/docs/books/effective/>
 
R

Roedy Green

First of all, the generic class will *not* know the actual
type used. At most you can enforce it to be a subclass or
superclasses of some given class.

If you to know the actual class, you will have to pass that as an
explicit class parameter somewhere, or find out the class dynamically
with getClass. Remember that all information about generics is washed
away by the compiler so at runtime, it is as if no generics were used.
All generics can really do is some additional cross-checks on how you
use combinations of classes, taking into consideration only
information that can be gleaned from types known at compile time.
 
L

Lew

Andreas Leitgeb wrote, quoted or indirectly quoted someone who said :
Roedy said:
If you to know the actual class, you will have to pass that as an
explicit class parameter somewhere, or find out the class dynamically
with getClass. Remember that all information about generics is washed
away by the compiler so at runtime, it is as if no generics were used.
All generics can really do is some additional cross-checks on how you
use combinations of classes, taking into consideration only
information that can be gleaned from types known at compile time.

Exactly so.

Let us not disparage "all [that] generic can really do", though. It is
significant. Once you get your type assertions right for the compiler, it is
impossible to have class-cast problems at run time. Also, the need to know
run=time type information is much rarer than one might think, if all the type
assertions are correct at compile time. Properly used, generics lock down a
program to a significantly more stable state.

When you do need type information at run time, one standard idiom is that
class parameter Roedy mentioned, a runtime type token (RTTT) similar to
(appropriate imports and static imports assumed):

/**
* Foo illustrates a run-time type token (RTTT).
* @param <T> base type of class.
*/
public class Foo <T>
{
private final Logger logger = getLogger( getClass() );

private final Class <T> rttt;
/**
* Constructor with run-time type token.
* @param tok Class {@code <T>} type token.
*/
public Foo( Class <T> tok )
{
if ( tok == null )
{
final String msg = "Run-time type token must not be null";
IllegalArgumentException fubar = new IllegalArgumentException( msg );
logger.error( msg, fubar );
throw fubar;
}
this.rttt = tok;
assert this.rttt != null;
}
// ... rest of the class
}

You can use the methods of 'rttt' to cast, check compatibility and do other
run-timey type thingies.
 
D

Daniel Pitts

If this is the recommended way to deal with a »rawtype«
warning, when one does not want to restrict the type
parameter to anything more special than »java.lang.Object«,
ok, I will do it.

I just had read advice before to use »< ?>« in such cases,
so I already have edited this into dozens of places. Ok,
so now I may go back and change it to »< T>«. I just want
a general and final solution, so that I will not have to
change this even more often.
I think maybe you misinterpreted Arne's suggestion, or I did.

I take his suggestion as:

interface MyInterface<T> {
void addrac(Comparable<T> container, int position);
}

class MyClassForFoo implements MyInterface<Foo> {
void addrac(Comparable<Foo> container, int position) {}
}


Another alternative, which may work equally well, depending on your
situation, but I doubt it will because of the method signature and lack
of other context in the parameters.


interface MyInterface {
<T>void addrac(Comparable<T> container, int position);
}

class MyClass implements MyInterface {
<T> void addrac(Comparable<T> container, int position) {
T t = container;
}
}
 
I

Ian

This is an informative explication of Joshua Bloch's maxim, PECS, an
acronym for producer-extends, consumer-super.

As a newbie, I found his choice of acronym absolutely hideous and
totally non-mnemonic.

I eventually settled on:

extract <-> extends
supply <-> super

tells you what to do & everything ;)

Ian.
 
M

markspace

As a newbie, I found his choice of acronym absolutely hideous and
totally non-mnemonic.

I eventually settled on:

extract <-> extends
supply <-> super


Except that producer and consumer are much more standard computer
science terms. (Type "producer consumer" into Google and see what you get.)
 
I

Ian

Except that producer and consumer are much more standard computer
science terms. (Type "producer consumer" into Google and see what you get.)

OK so you've outed a newbie (I studied engineering, not computer science) ;)

Ian.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top