Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / March 2006

Tip: Looking for answers? Try searching our database.

Fun with generics

Thread view: 
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 Magazines

Get 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 ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.