Dimitri Maziuk said:
The goal of generics is to communicate the type of a collection
element to the compiler, so it can be checked (quoting Sun). That's
all I'm doing.
I think you've run into a problem with Sun's not particularly general
description of the purpose of generics. Generics are used by the
collections API to allow you to communicate the type of a collection.
Since most people come across generics in the context of the collections
API, it makes some sense for Sun to say that (depending on context,
which I didn't see)... but it's an incomplete statement.
In your case, you already know the basic type of the collection (it's
ColHdr), so what you need to communicate is the type parameter to
ColHdr. The way you do that is with a type parameter to Table, as such:
public interface Table<C>
{
...You
You mean I can't do this:
class Foo<T extends ArrayList<Comparable<T>>>
No, I mean you can't do this:
class Foo<ArrayList<Comparable<T>>> ...
That doesn't work, because the Java language requires that the formal
type parameter list following a class declaration consists of actual
type parameters. You seem to want to declare type parameters in context
and have the compiler match that against type names in a kind of pattern
matching, and you just can't do it that way.
Your code above, though, with some additions, does make sense:
class Foo<T extends ArrayList<Comparable<T>>>
{
public void doSomethingWith(T t) { ... }
public T getSomething() { ... }
}
This says that there's a type called T, and that T is constrained to be,
or to be is a subclass of, ArrayList<Comparable<T>>. Subclasses of
ArrayList are rather rare, but nevertheless you can do this. Its
advantage (though a little dubious) over just writing a non-generic Foo
using ArrayList is that if someone wants to create a Foo that only works
with instances of the subclass javax.management.AttributeList (which
subclasses ArrayList), they can do so, and they can be assured that the
compiler will complain if they pass anything else, and that they don't
need an explicit cast on the result of getSomething().
Note that this only makes sense if you expect someone to use Foo in such
a way that it's important that it only works with some subclass of
ArrayList. Otherwise, you wouldn't write a generic class. (Also, you
probably want a wildcard in the type parameter to Comparable, but that's
a different matter.)
What I can't do is
class Foo<C extends ArrayList<Comparable<T>>> -- error, cannot resolve
symbol T.
Yep, because you haven't declared T.
However, I can fake it by
class Foo<T, C extends List<Comparable<T>>>
That is, in fact, not just faking it, but rather doing what you might
have meant to begin with.
In other words, I can do "Table<C, ColHdr<C>>", it's just that
syntax is ugly.
You mean that you could do:
interface Table<C, T extends ColHdr<C>> { ... }
Yes, you can, but I don't think you want to. Do you expect people to
subclass ColHdr? If they do, is it important when they use a table that
they remember exactly which subclass of ColHdr they chose? If the
answer to both of these questions is yes, then the above is what you
want. Otherwise, you really want this simpler code:
interface Table said:
(See also C++ "typename" keyword.)
Why would I see the C++ typename keyword? These are generics in Java.
They have very little to do with templates in C++, aside from solving
some of the same problems and using a similar syntax. The core concepts
are very different. For example, there is no such thing as type bounds
or erasures in C++.
Watch the quoting. My comment referred to this code:
interface Foo said:
No, in the code above, it's the name of a formal type parameter. It has
nothing at all to do with java.lang.Iterable. That was why I said the
code is very poor. But yes, I understand that you wanted it to be
java.lang.Iterable. I'm trying to explain that you are miunderstanding
the purpose of generics when you want that. One more example:
It is perfectly reasonable to want to tell the
compiler that my home-grown collection Foo takes only Iterable elements
Then do it this way:
class Foo
{
public void add(Iterable t) { ... }
public Iterable get(int i) { ... }
...
}
If you want your class to contain only Iterable elements, then you don't
need generics. If you'd like to implement an existing generic
interface, though, then you can do so like this:
class Foo implements Collection said:
-- and I can, except the syntax is ridiculous: nobody would want to
actually _extend_ Iterable, as syntax suggests.
I presume you mean: class Foo<T extends Iterable> { ... }
The syntax suggests that for a good reason. Declaring a class like that
suggests that someone does indeed want to extend the type Iterable, and
that they want to use Foo while remaining aware of the specific subtype
with respect to which this Foo instance if used. Otherwise, you'd write
the non-generic Foo implementation I provided above.
(Again, cf. C++ template specialization.)
Java does not implement C++ template specialization. It is not a
compatible concept with Java generics. Again, generics and C++
templates are conceptually different things, so ideas don't move over
wholesale from one to the other.
Yes, but this is also stupid: Foo is not a collection of T, it
is a collection of Iterable<T>.
The unknown type is T. Therefore, you specify T as the type parameter.
You've definitely gotten too hung up on an incomplete statement in some
tutorial on generics.
But you can't adequately express that in current syntax.
Of course you can. If you don't like the syntax, that's your problem,
and it's aesthetic/psychological rather than technical in nature.
Besides,
interface Foo {
<T> setBar( Iterable<T> t );
}
is just as valid,
Except it means something different. Your form allows:
Iterable<String> a = ...;
Iterable<Number> b = ...;
Foo f = new Foo();
f.setBar(a);
f.setBar(b);
The generic Foo above would look like this:
Iterable<String> a = ...;
Iterable<Number> b = ...;
Foo<String> f = new Foo<String>();
f.setBar(a); // OK
f.setBar(b); // ERROR
As a side note, you may want to have written this instead:
interface Foo<T>
{
void setBar(Iterable<? extends T> t);
}
My original code was copying yours closely to make the point, but it's
really better to use the wildcard in that situation.
(ISTR Bruce Eckel making a similar
argument when generics first came out.)
I don't recall what Bruce Eckel said. He may have said that the problem
generics solve is not serious, and I may agree with him in some
contexts. But I'd bet a kidney that he didn't say what you're saying in
this thread.
--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation