Java Forum / General / March 2006
Fun with generics
Dimitri Maziuk - 20 Mar 2006 23:00 GMT Let's say I want to write a table that may be backed by an SQL table or by in-memory store. The table is a list of column headers and a list of rows. public interface ColHdr<C> { String getName(); int getWidth(); C getType(); } -- where type will be implementation-specific, say, an enum.
Rows may be a simple list of String [] or something else iterable. So, public interface Table<R implements Iterable,ColHdr<C>> { R getRows(); List<ColHdr<C>> getCols(); } That doesn't compile. What compiles is public interface Table<R extends Iterable,C> { R getRows(); List<ColHdr<C>> getCols(); } which is not really what the table is about: its second parameter should not be a "column type" (C), it should be a "column header that uses C for column type". public interface Table<R extends Iterable,ColHdr> compiles but loses the <C> -- not quite what I wanted either.
Anyone knows how to declare an interface that takes one formal type parameter and one type that is itself generic?
Dima (While we're at it, I wonder who came up with public class bar extends Iterable <-- error, of course public class bar implements Iterable <-- that's how you do it, but public interface foo<T implements Iterable> <-- error public interface foo<T extends Iterable> <-- ruh-iight)
 Signature Yes, Java is so bulletproofed that to a C programmer it feels like being in a straightjacket, but it's a really comfy and warm straightjacket, and the world would be a safer place if everyone was straightjacketed most of the time. -- Mark 'Kamikaze' Hughes
Oliver Wong - 20 Mar 2006 23:21 GMT > Let's say I want to write a table that may be backed by an SQL table > or by in-memory store. The table is a list of column headers and a [quoted text clipped - 22 lines] > public interface Table<R extends Iterable,ColHdr> > compiles but loses the <C> -- not quite what I wanted either. How about: <code> public interface ColHdr<C> { String getName(); int getWidth(); C getType(); }
public interface Table<R extends Iterable,ColHeads extends ColHdr<?>> { R getRows(); List<ColHeads> getCols(); } </code>
You're not using the C in your code for Table, so it doesn't need to be specified.
> Anyone knows how to declare an interface that takes one formal > type parameter and one type that is itself generic? [quoted text clipped - 6 lines] > public interface foo<T implements Iterable> <-- error > public interface foo<T extends Iterable> <-- ruh-iight) A class can't extend an interface. An interface can extend an interface. A type can extend an interface. T is a type, not a class. But I'm not even sure why you would need two different keywords, "extends" and "implements". If we had only a single keyword for both situations, would there be any ambiguity?
I don't know who came up with it though.
- Oliver
Oliver Wong - 20 Mar 2006 23:25 GMT > How about: > <code> [quoted text clipped - 9 lines] > } > </code> After thinking about it a bit, maybe you were trying something like this?
<code> public interface ColHdr<C> { String getName(); int getWidth(); C getType(); }
public interface Table<C, R extends Iterable<C>,ColHeads extends ColHdr<C>> { R getRows(); List<ColHeads> getCols(); } </code>
That is, the getType method returns the type that you're iterating over? It wasn't clear to me if this was your intent or not.
- Oliver
Thomas Hawtin - 21 Mar 2006 00:02 GMT > public interface Table<C, R extends Iterable<C>,ColHeads extends > ColHdr<C>> { > R getRows(); > List<ColHeads> getCols(); > } Or more generally:
public interface Table< C, R extends Iterable<? extends C>, ColHeads extends ColHdr<? extends C> > { R getRows(); List<ColHeads> getCols(); }
If you don't mind it being used in a contrary way:
public interface Table< R extends Iterable<?>, ColHeads extends ColHdr<?> > { R getRows(); List<ColHeads> getCols(); }
Or even:
public interface Table< R, ColHeads > { R getRows(); List<ColHeads> getCols(); }
Tom Hawtin
 Signature Unemployed English Java programmer http://jroller.com/page/tackline/
Dimitri Maziuk - 21 Mar 2006 00:35 GMT Thomas Hawtin sez:
>> public interface Table<C, R extends Iterable<C>,ColHeads extends >> ColHdr<C>> { [quoted text clipped - 12 lines] > List<ColHeads> getCols(); > } Nope. All I want is public interface Table<ColHdr<C>> and "ColHdr" is what causes compiler error, with or without "? extends".
As for "extends Iterable", that was just a side comment: sure, you can declare interface Foo<Iterable> { <T> void setBar( Iterable T ); } but wouldn't this interface Foo<Iterable T> { // or "<T implements Iterable>" void setBar( T ); } be much clearer?
Dima
 Signature True courage comes from steadying yourself and forcing yourself to ssh into the fscking thing yet again and not admitting that it doesn't care what it's done to your life. -- "Hidden among the nodes" by ADB
Hendrik Maryns - 21 Mar 2006 13:31 GMT -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 NotDashEscaped: You need GnuPG to verify this message
Dimitri Maziuk schreef:
> Thomas Hawtin sez: >>> public interface Table<C, R extends Iterable<C>,ColHeads extends >>> ColHdr<C>> { >>> R getRows(); >>> List<ColHeads> getCols(); >>> }
> Nope. All I want is Why don?t you start over again and explain _exactly_ what you?re trying? It?s such a mess now, that I cannot even try to help you.
H.
 Signature Hendrik Maryns
================== www.lieverleven.be http://aouw.org
Dimitri Maziuk - 21 Mar 2006 18:21 GMT Hendrik Maryns sez:
> -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 [quoted text clipped - 12 lines] > Why don?t you start over again and explain _exactly_ what you?re trying? > It?s such a mess now, that I cannot even try to help you. My theory is that thanks to RTTE Foo<Bar<T>> becomes Foo<Bar>, at which point <T> causes compiler error. Or something. Anyway, looks like it can't be done and I'm redesigning the interface instead.
Dima
 Signature ...the mainstream products of major vendors largely ignore these demonstrated technologies... [Instead, their customers] are left with several ineffective solutions collected under marketing titles like "defense in depth". -- Thirty Years Later: Lessons from the Multics Security Evaluation
Hendrik Maryns - 23 Mar 2006 13:52 GMT -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 NotDashEscaped: You need GnuPG to verify this message
Dimitri Maziuk schreef:
> Hendrik Maryns sez: >> -----BEGIN PGP SIGNED MESSAGE----- [quoted text clipped - 13 lines] > > My theory is that thanks to RTTE Foo<Bar<T>> becomes Foo<Bar>, No, it becomes Foo.
> at which point <T> causes compiler error. If it causes a compiler error, then it can have nothing to do with RTTE (took me a while to guess this is run-time type erasure), as the first two letters imply.
Or something.
Indeed. Do read up on generics.
> Anyway, looks like it can't be done and I'm redesigning the > interface instead. That?s the other way. But you take you arse with you, as this nice Russian proverb says.
H.
 Signature Hendrik Maryns
================== www.lieverleven.be http://aouw.org
Chris Smith - 22 Mar 2006 18:11 GMT > Nope. All I want is > public interface Table<ColHdr<C>> > and "ColHdr" is what causes compiler error, with or without "? extends". That's just not a sensible thing to want. ColHdr is an actual class. A name for a type parameter is syntactically supposed to go there. You can't use a real class as a type parameter -- if that's what you wanted, you'd just leave out the type parameter and use the real type.
Table is parameterized on C, not on ColHdr<C>. The fact that it only uses C in order to work with values of ColHdr<C> is not really relevant here. It's C that is the unknown type, so C needs to be the type parameter.
Now, what problem do you think that's causing? If you explain something you want to do (in a functional, not syntactic, sense) and can't, then that provides a starting point for helping you out.
> As for "extends Iterable", that was just a side comment: sure, you can > declare > interface Foo<Iterable> { > <T> void setBar( Iterable T ); > } This would be very bad code. Iterable is the name of a standard library interface. Shadowing it with a type parameter name is quite confusing. I think you're somehow confused and you believe that Iterable above actually has something to do with the standard library interface... but I'm not entirely sure.
> but wouldn't this > interface Foo<Iterable T> { // or "<T implements Iterable>" > void setBar( T ); > } > be much clearer? Certainly this is quite valid:
interface Foo<T extends Iterable<?>> { void setBar(T t); }
and this is valid:
interface Foo<T> { void setBar(Iterable<T> t); }
I'm not sure which you mean.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
Dimitri Maziuk - 22 Mar 2006 21:23 GMT Chris Smith sez:
>> Nope. All I want is >> public interface Table<ColHdr<C>> >> and "ColHdr" is what causes compiler error, with or without "? extends". > > That's just not a sensible thing to want. ColHdr is an actual class. A > name for a type parameter is syntactically supposed to go there. Huh? A Table is a colection of column headers and rows. ColHdr is a type (an inteface, BTW, may or may not be quite the same as your definition of "actual class").
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.
...You
> can't use a real class as a type parameter -- if that's what you wanted, > you'd just leave out the type parameter and use the real type. You mean I can't do this:
class Foo<T extends ArrayList<Comparable<T>>>
-- javac seems to disagree with you there.
What I can't do is class Foo<C extends ArrayList<Comparable<T>>> -- error, cannot resolve symbol T. However, I can fake it by class Foo<T, C extends List<Comparable<T>>>
In other words, I can do "Table<C, ColHdr<C>>", it's just that syntax is ugly. (See also C++ "typename" keyword.)
... <T extends Iterable>
> This would be very bad code. Iterable is the name of a standard library > interface. Shadowing it with a type parameter name is quite confusing. Iterable is a type. It is perfectly reasonable to want to tell the compiler that my home-grown collection Foo takes only Iterable elements -- and I can, except the syntax is ridiculous: nobody would want to actually _extend_ Iterable, as syntax suggests. (Again, cf. C++ template specialization.)
> and this is valid: > > interface Foo<T> > { > void setBar(Iterable<T> t); > } Yes, but this is also stupid: Foo is not a collection of T, it is a collection of Iterable<T>. But you can't adequately express that in current syntax. Besides,
interface Foo { <T> setBar( Iterable<T> t ); }
is just as valid, so in practice there's no advantage to generifying the type Foo itself. (ISTR Bruce Eckel making a similar argument when generics first came out.)
Dima
 Signature We're part of that admittedly-too-small group that is trying to save the human race from itself. With any luck, we'll fail abjectly and the cockroaches will win out. -- Mike Andrews
Oliver Wong - 22 Mar 2006 22:01 GMT > ...You >> can't use a real class as a type parameter -- if that's what you wanted, [quoted text clipped - 5 lines] > > -- javac seems to disagree with you there. No, what he means is you can't do this:
class Foo<ArrayList> { public ArrayList getMyThing() {...} }
I.e. you can't specify an "actual class" (where ArrayList is an example of an actual class), because if you knew ahead of time what actual class you wanted, you could just put it directly into the code (as seen here in "public ArrayList getMyThing()". Generics are for when you DON'T know the type, as in:
class Foo<T> { public T getMyThing() {...} }
> ... <T extends Iterable> >> This would be very bad code. Iterable is the name of a standard library [quoted text clipped - 5 lines] > actually _extend_ Iterable, as syntax suggests. (Again, cf. C++ > template specialization.) Chris was subtly saying that the code you provided doesn't mean what you think it means. You've declared a new generic type variable called "Iterable", when you probably mean to refer to the existing Iterable. It's similar to this mistake:
class Foo { int x;
public void someMethod() { int x; //shadowing is occuring here. } }
Instead of referring to the existing field called "x", you've created a new local variable called "x".
Also, for claritiy, here's the code Chris was referring to as being "bad" and in which shadowing is occuring (which seems to have gotten snipped)
<quote> interface Foo<Iterable> { <T> void setBar( Iterable T ); } </quote>
>> and this is valid: >> [quoted text clipped - 6 lines] > is a collection of Iterable<T>. But you can't adequately express > that in current syntax. The question is, what is it that's generic? Is it what specific subclass of Iterable that's in use that is generic? If so, then the code should be
interface Foo<T extends Iterable<?>> { void setBar(T t); }
Or is it the type of Iterable which is generic? If so, then the code should be as Chris posted above. Generics are not used only for collections, which is why it doesn't make sense to restriction the conceptual definition of generics as "the type of elements contained in a collection".
> Besides, > [quoted text clipped - 5 lines] > generifying the type Foo itself. (ISTR Bruce Eckel making a similar > argument when generics first came out.) Well, no, it's not valid. You need to specify a return type for the setBar() method. But let's pretend you specified that it returns T, for example.
It does something different from the rest of the code posted in this thread. It's like saying the "Hello World!" program is just as much "valid Java" as the "Azureus" program. Yes, they both consist of Java code, but they do two different things.
- Oliver
Dimitri Maziuk - 22 Mar 2006 23:43 GMT Oliver Wong sez:
>> ...You >>> can't use a real class as a type parameter -- if that's what you wanted, >>> you'd just leave out the type parameter and use the real type. ...
> No, what he means is you can't do this: > [quoted text clipped - 7 lines] > "public ArrayList getMyThing()". Generics are for when you DON'T know the > type Yes, precisely. I don't know the type of E in "class Foo<ArrayList<E>>" and that's what I want to tell the compiler.
And I can get it to compile with class Foo<T, C extends ArrayList<T>>
Except it won't actually do what generics are supposed to: a Foo<String, ArrayList<String>> will happily take an Integer due to RTTE.
> Chris was subtly saying that the code you provided doesn't mean what you > think it means. You've declared a new generic type variable called > "Iterable", when you probably mean to refer to the existing Iterable. First of all, if that were true I'd get a "Cannot resolve symbol Iterable". Secondly, the compiler will let me use that field in foreach loop (sans the cast to Object thanks to RTTE). Finally, if I replace ArrayList with Iterable in my Foo, it'll actually run just as nicely (FVO "nicely" = "casting Strings to Objects) as before.
So it's pretty safe to suggest that you think again (dunno about Chris).
As for your other question, both. As in Table< ROWS extends List< ROW extends List< CELLSTORAGE > >, COLS extends List< CELLTYPE > >
Dima
 Signature Relativity, Uncertainty, Incompleteness, Undecidability: choose any four
Chris Smith - 23 Mar 2006 00:02 GMT > Yes, precisely. I don't know the type of E in "class Foo<ArrayList<E>>" > and that's what I want to tell the compiler. Then here's how you do it:
class Foo<E>
You can now use ArrayList<E> to your heart's content, and it will work just fine.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
Oliver Wong - 23 Mar 2006 00:03 GMT > Oliver Wong sez: >> [quoted text clipped - 18 lines] > Yes, precisely. I don't know the type of E in "class Foo<ArrayList<E>>" > and that's what I want to tell the compiler. That's like saying "I don't know the type of E in 'fsdljfskdjfsdf'". What you wrote is not legal Java, and so doesn't make sense. I'm guessing what you MEANT to say is something like this:
<paraphrasing> I don't know the type of E in:
interface Foo [don't know what to write here] { public ArrayList<E> getArray(); } </paraphrasing>
And I'd answer:
<answer> Okay, so you need to write code like this:
interface Foo<E> { public ArrayList<E> getArray(); } </answer>
If you protest "But Foo is not a collection of E!", I would reply "Foo isn't a collection at all; but the unknown type is E, and that's what why you write Foo<E>. 'Cause it's E that's unknown, not ArrayList which is unknown."
> And I can get it to compile with > class Foo<T, C extends ArrayList<T>> > > Except it won't actually do what generics are supposed to: a > Foo<String, ArrayList<String>> will happily take an Integer due > to RTTE. I'm not sure what YOU think generics is supposed to do, but probably "Class Foo<T, C extends ArrayList<T>>" does exactly what it says it does (unless there's a bug in your compiler).
When you say "Foo<String, ArrayList<String>> will happily take an Integer", maybe you could post an SSCCE showing where exactly this Integer will show up, and I can try to show you how to rewrite the code to disallow this Integer from showing up there.
>> Chris was subtly saying that the code you provided doesn't mean what >> you [quoted text clipped - 3 lines] > First of all, if that were true I'd get a "Cannot resolve symbol > Iterable". No, if it were true, you'd get a program which compiled fine, but in which name shadowing occured. It shouldn't say "Cannot resolve symbol Iterable", because you DID declare the Iterable symbol.
> Secondly, the compiler will let me use that field in foreach loop (sans > the cast to Object thanks to RTTE). Finally, if I replace ArrayList with > Iterable in my Foo, it'll actually run just as nicely (FVO "nicely" = > "casting Strings to Objects) as before. > > So it's pretty safe to suggest that you think again (dunno about Chris). From reading Chris' reply to your post elsewhere in the thread, I'm fairly confident I had guessed correctly at what Chris meant.
> As for your other question, both. As in > Table< ROWS extends List< ROW extends List< CELLSTORAGE > >, > COLS extends List< CELLTYPE > > What's "CELLSTORAGE" in this case? Would this be the same as CELLTYPE?
- Oliver
Chris Smith - 22 Mar 2006 23:45 GMT > 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> { public void doSomethingWith(ColHdr<C> header); }
> ...You > > can't use a real class as a type parameter -- if that's what you wanted, [quoted text clipped - 3 lines] > > 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<C> { ... use ColHdr<C> here ... }
> (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++.
> ... <T extends Iterable> > > This would be very bad code. Iterable is the name of a standard library > > interface. Shadowing it with a type parameter name is quite confusing. Watch the quoting. My comment referred to this code:
interface Foo<Iterable> { ... }
> Iterable is a type. 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<Iterable> { ... }
> -- 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.
> > and this is valid: > > [quoted text clipped - 5 lines] > 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, > [quoted text clipped - 3 lines] > > 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.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
Dimitri Maziuk - 23 Mar 2006 02:23 GMT Chris Smith sez:
>> 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. Sort of. They didn't exactly enumerate things you can and cannot do with generics, so I'm poking at it to see what breaks.
> 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 and my comment was that it's ugly because conceptually C is the type parameter to ColHdr, Table itself should not care. What would make sense for the Table is to limit the column header types. So: Table<H extends ColHdr>
Since ColHdr is generic itself, this becomes Table<H extends ColHdr<C>> -- where I get to "undeclared C".
Next,
> Your code above, though, with some additions, does make sense: > > class Foo<T extends ArrayList<Comparable<T>>> Yep, except "T extends ArrayList<T>" makes my brane hurt because it looks like it says "type T is a kind of ArrayList of type T (see also recursion)". So I'd rather go with
>> 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. Well, it's faking it in the sense that it shuts up the compiler. Running that is a different story. (I also have an esthetic objection to declaring C that isn't used, but that pales in comparison with RTTE.)
...
> 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? It was an interface, I expect them to implement it.
...If they do, is it important when they use a table that
> they remember exactly which subclass of ColHdr they chose? No, I want exactly what generics is supposed to do: tell the compiler that my Table collection is a collection of elements of type ColHdr.
...
> 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. He said more or less this:
> If you want your class to contain only Iterable elements, then you don't > need generics. And it's pretty much what I ended on. I can't help noticing the oxymoron, however:
"the goal of generics is to communicate the type of a collection element to the compiler so it can be checked. If you want your collection to contain only Iterable elements, then you don't need generics".
...
> interface Foo<Iterable> { ... } > >> Iterable is a type. > > No, in the code above, it's the name of a formal type parameter. Right, my bad, I guess. My original comment was that <T extends Iterable> is not the best choice of syntax and it'd be nice if they made it consistent with type declarations: allow "implements X" as well as "extends Y" in there. Or -- much cleaner -- to just write <Iterable> and disambiguate formal type parameters with <typename T>.
Dima
 Signature Double d = new Double(2.0); d = new Double(d.doubleValue() * d.doubleValue()); I regard Double variables as mutable, considering this one started as 2.0 and ended up as 4.0. -- Brendan Guild
Chris Smith - 23 Mar 2006 05:21 GMT Just a few more comments.
> > 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 > > and my comment was that it's ugly because conceptually C is the type > parameter to ColHdr, Table itself should not care. Both conceptually and actually, C itself is a type parameter to Table. Whatever type C represents will also become a type parameter to ColHdr. You seem to be drawing some kind of distinction here that doesn't make much sense to me, and you've apparently decided that C shouldn't be a type parameter to Table, even though Table needs to use the type (even if only to use specific instances of ColHdr types) and doesn't already know what it is.
Perhaps a C++ example would be more to your liking. std::map<K,V> takes two type parameters K and V, even though it's really (at least conceptually) a collection of std::pair<K,V>. Despite that, it is still not declared with "template<class std::pair<K,V>>".
In any case, you simply can't write the code you apparently want to write. Or rather, you can, but it won't compile.
> ...If they do, is it important when they use a table that > > they remember exactly which subclass of ColHdr they chose? > > No, I want exactly what generics is supposed to do: tell the > compiler that my Table collection is a collection of elements > of type ColHdr. Then Table<C> it is.
Since you're writing Table, you don't do that with generics. You do that by having your methods receive and return variables of type ColHdr. Generics solve a different problem; if, for example, you wanted to write Table without deciding what it is a collection of, and then wanted someone else later on to inform the compiler that it's a collection of ColHdr, *then* you would want to use generics to declare that type.
As it is, then, you don't want to use generics to declare the thing that a Table holds -- because it's always ColHdr, and the client code doesn't need the Table to remember which implementing class of ColHdr is being used. The only thing you need generics for, then, is to tell the compiler what exact kind of ColHdr to use. That's C in our discussion until now, so C is your type parameter.
> [Bruce Eckel] said more or less this: > [quoted text clipped - 7 lines] > to the compiler so it can be checked. If you want your collection to > contain only Iterable elements, then you don't need generics". Bruce Eckel's statement, then, while correct, seems to be about something different. Bruce is talking from the client standpoint... and he's right; with a few simple casts, generics are not needed. When I said generics aren't needed, though, I meant something different... you really get NO benefit from using a type parameter in that case. Bruce Eckel is talking about whether the language feature of type parameters is helpful, but I'm saying that your specific type parameter right there is not helpful.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
Dimitri Maziuk - 23 Mar 2006 21:44 GMT Chris Smith sez: ...
> Perhaps a C++ example would be more to your liking. std::map<K,V> takes > two type parameters K and V, even though it's really (at least > conceptually) a collection of std::pair<K,V>. Despite that, it is still > not declared with "template<class std::pair<K,V>>". Because it isn't. Map's job in life is to associate keys with values, its function is "V get( K )". There's no pair in there.
A C++ example more to my liking is template<typename K, template <typename U, typename V> class pair> class PairMap
Dima
 Signature We're sysadmins. Sanity happens to other people. -- Chris King
Chris Smith - 24 Mar 2006 01:55 GMT > A C++ example more to my liking is > template<typename K, template <typename U, typename V> class pair> > class PairMap It may be to your liking, but it does something different than what you've been asking about on this newsgroup. Just like the Iterable example earlier, you have managed to hide std::pair, in the code above, with a template parameter named pair. That template parameter is expected to be a type that requires two template parameters of its own, but a specific instantiation of the PairMap template does not contain information about the values of U and V.
In other words, if you want to have a map to a specific kind of pair, you'd have to do this instead:
template<typename K, typename A, typename B, template <typename U, typename V> class pair> class PairMap { // use pair<A,B> as the pair type }
or, if you really didn't intend to provide for your client code to provide an alternative implementation instead of std::pair, then you'd do this instead:
template<typename K, typename A, typename B> class PairMap { // use std::pair<A,B> as the pair type }
And that looks surprisingly like the Java code everyone has been telling you to write.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
Dimitri Maziuk - 21 Mar 2006 00:13 GMT Oliver Wong sez:
><code> > public interface ColHdr<C> { > String getName(); > int getWidth(); > C getType(); > } public interface Table<R,ColHeads extends ColHdr<C>> { List<ColHeads> getCols(); } is not it: ColHeads would be a List<ColHdr<C>> and it wouldn't fix the problem.
<R,List<ColHdr<C>>> doesn't work any better than <R,ColHdr<C>>.
Plus, public interface Table<R,T extends ColHdr<C>> { public List<ColHdr<C>> getColumns(); } complains that it "cannot find symbol class C" (besides the unused "T". This looks the problem that C++ solves with "typename" keyword, BTW). Method declaration can be fixed: public <C> List<ColHdr<C>> getColumns(); but that does not seem to work for interface declaration.
It get better: public abstract class Table<C> { public abstract List<ColHdr<C>> getColumns(); } was OK as interface declaration, but is not OK as a class.
> public interface Table<C, R extends Iterable<C>,ColHeads extends > ColHdr<C>> { [quoted text clipped - 5 lines] > That is, the getType method returns the type that you're iterating over? It > wasn't clear to me if this was your intent or not. No, it's a table. I'm iterating over _rows_, and I should have left that bit out for simplicity's sake when I posted it (my code above has just "R", without "extends Iterable").
getType() returns _column_ type. Each column has a "header" that remembers its name, size, and type. That type is the "C". It can be e.g. "rcsb([:upper:]|[:digit:]){6}" -- just to give an example.
Dima
 Signature ... with the exception of January and February 1900, all Microsoft application libraries counted dates the same way. -- An Interview with Joel Spolsky of JoelonSoftware
Ian Pilcher - 21 Mar 2006 00:33 GMT > public interface ColHdr<C> { > String getName(); > int getWidth(); > C getType(); > } Shouldn't that be "Class<C> getType()"?
 Signature ======================================================================== Ian Pilcher i.pilcher@comcast.net ========================================================================
Dimitri Maziuk - 21 Mar 2006 01:24 GMT Ian Pilcher sez:
>> public interface ColHdr<C> { >> String getName(); [quoted text clipped - 3 lines] > > Shouldn't that be "Class<C> getType()"? Not according to my compiler.
Dima
 Signature Politics and religion are just like software and hardware. They all suck, the documentation is provably incorrect, and all the vendors tell lies. -- Andrew Dalgleish
Hendrik Maryns - 21 Mar 2006 13:30 GMT -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 NotDashEscaped: You need GnuPG to verify this message
Dimitri Maziuk schreef:
> Ian Pilcher sez: >>> public interface ColHdr<C> { [quoted text clipped - 5 lines] > > Not according to my compiler. It?s not about what you compiler wants, it?s about what you want to do with the method. If you want to tell the client what the type of the columns is, then Ian?s suggestion is right. If you want to return some element from the column, then leave it as is.
H.
 Signature Hendrik Maryns
================== www.lieverleven.be http://aouw.org
Chris Smith - 22 Mar 2006 18:12 GMT > It?s not about what you compiler wants, it?s about what you want to do > with the method. If you want to tell the client what the type of the > columns is, then Ian?s suggestion is right. If you want to return some > element from the column, then leave it as is. In the original post, Ian already explained that C is an enum of types, and getType returns a value of that enum. The original code seems to be correct in this regard.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
Ian Pilcher - 22 Mar 2006 18:21 GMT > In the original post, Ian already explained that C is an enum of types, > and getType returns a value of that enum. The original code seems to be > correct in this regard. Actually, Ian was the person who missed that fact.
 Signature ======================================================================== Ian Pilcher i.pilcher@comcast.net ========================================================================
Rémi Bastide - 21 Mar 2006 18:28 GMT > Let's say I want to write a table that may be backed by an SQL table > or by in-memory store. The table is a list of column headers and a [quoted text clipped - 12 lines] > List<ColHdr<C>> getCols(); > } I do not understand how you plan to instantiate these generic definitions to get a real table, could you give an example ?
 Signature Rémi Bastide http://liihs.irit.fr/bastide
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|