question on generics in class type declarations

R

Roger Levy

I have a simple problem using generics. Suppose I want to make a
parameterized holder class, call it Singleton, that contains a single
object o, and instances of Singleton containing objects of comparable
type should themselves be comparable by these objects. So I want
something like

public class Singleton<T1 extends Comparable<? super T1>> implements
Comparable<Singleton<T2>> {
T1 x;

public int compareTo(Singleton<T2> s) {
return x.compareTo(s.x);
}

}

while constraint that T1 and T2 are themselves mutually comparable.
At any rate, the above is not legal Java 1.5 code.

Any suggestions will be much appreciated!

Many thanks,

Roger Levy
 
L

Larry Barowski

Roger Levy said:
I have a simple problem using generics. Suppose I want to make a
parameterized holder class, call it Singleton, that contains a single
object o, and instances of Singleton containing objects of comparable
type should themselves be comparable by these objects. So I want
something like

public class Singleton<T1 extends Comparable<? super T1>> implements
Comparable<Singleton<T2>> {
T1 x;

public int compareTo(Singleton<T2> s) {
return x.compareTo(s.x);
}

}

while constraint that T1 and T2 are themselves mutually comparable.
At any rate, the above is not legal Java 1.5 code.

How about this?

class Singleton<T1 extends Comparable<? super T1>> implements
Comparable<Singleton<? extends Comparable<? super T1>>> {
T1 x;

public int compareTo(Singleton<? extends Comparable<? super T1>> s) {
return s.x.compareTo(x);
}
}
 
J

Jesper Nordenberg

I have a simple problem using generics. Suppose I want to make a
parameterized holder class, call it Singleton, that contains a single
object o, and instances of Singleton containing objects of comparable
type should themselves be comparable by these objects. So I want
something like

public class Singleton<T1 extends Comparable<? super T1>> implements
Comparable<Singleton<T2>> {
T1 x;

public int compareTo(Singleton<T2> s) {
return x.compareTo(s.x);
}

}

while constraint that T1 and T2 are themselves mutually comparable.
At any rate, the above is not legal Java 1.5 code.

Any suggestions will be much appreciated!

If I understand correctly you want:

public class Singleton<T1 extends Comparable<T2>> implements
Comparable<Singleton<? extends T2>> {

where T2 is automatically inferred by the compiler. This is not
supported by the compiler though, so I don't think you can solve your
problem without introducing new type parameters to the Singleton class
which you probably don't want to do. The best I could come up with is:

public class Singleton<T1 extends Comparable<? super T1>> implements
Comparable<Singleton<? extends T1>> {
private T1 x;

public int compareTo(Singleton<? extends T1> s) {
return x.compareTo(s.x);
}

}

which fails in this example:

class A implements Comparable<A>
class B extends A
class C extends A
new Singleton<B>().compareTo(new Singleton<C>()); // Compile error!

/Jesper Nordenberg
 
S

Sudsy

Larry Barowski wrote:
How about this?

class Singleton<T1 extends Comparable<? super T1>> implements
Comparable<Singleton<? extends Comparable<? super T1>>> {
T1 x;

public int compareTo(Singleton<? extends Comparable<? super T1>> s) {
return s.x.compareTo(x);
}
}

Ye gods! Is the idea to make Java code as unreadable as C++ using
prototypes? This is so incredibly UGLY...
 
R

Roger Levy

Larry Barowski said:
How about this?

class Singleton<T1 extends Comparable<? super T1>> implements
Comparable<Singleton<? extends Comparable<? super T1>>> {
T1 x;

public int compareTo(Singleton<? extends Comparable<? super T1>> s) {
return s.x.compareTo(x);
}
}

Thank you! This works.

It appears that the problem with my version is that although we have
stipulated that the type of x extends Comparable<T1A super T1> and the
type of s.x extends Comparable<T1B super T1> for some T1A and T1B, we
have no guarantee that the type of s.x extends T1A. This seems to me
like a shortcoming of the syntax of generics for Java 1.5, what does
anyone else think?

Thanks again.

Roger
 
R

Roger Levy

Sudsy said:
Larry Barowski wrote:


Ye gods! Is the idea to make Java code as unreadable as C++ using
prototypes? This is so incredibly UGLY...

It _is_ pretty ugly at first glance. But the payoff is that with this
API and implementation, you will never, ever get a CastClassException
upon invoking the Singleton.compareTo() method. All errors will show
up at compile time. If Singleton (or an analogous class) is widely
used, this is a huge payoff in coding clarity. The ugliness is
contained to the Singleton class type declaration and the signature of
one method, and it can be clarified with careful documentation. I'll
take that tradeoff any day.

Roger
 
S

Sudsy

Roger said:
Sudsy <[email protected]> wrote in message news:<[email protected]>...
It _is_ pretty ugly at first glance. But the payoff is that with this
API and implementation, you will never, ever get a CastClassException
upon invoking the Singleton.compareTo() method. All errors will show
up at compile time. If Singleton (or an analogous class) is widely
used, this is a huge payoff in coding clarity. The ugliness is
contained to the Singleton class type declaration and the signature of
one method, and it can be clarified with careful documentation. I'll
take that tradeoff any day.

Roger,
Here's my problem: if I define a class or interface appropriately, I
don't NEED these artifical constructs. Let's be honest with the genesis
of prototypes: they evolved as a convenience for C++ programmers. It was
so they wouldn't need to code multiple methods which only differed in
the passed arguments and the returned type.
Am I wrong? Here's a quote from "Practical C++" (ISBN 0-7897-2144-9):
"Templates provide an incredible amount of power for C++ programmers,
allowing you to write generic code that will work with multiple data
types. In abstract terms, templates are parameterized types. A template
uses the parameter or parameters sent to it to define a new data type,
called a specialization of the template, at compile time."
Given that C++ is a pre-processing veneer applied to "standard" C,
I can understand the convenience of the short-cut. But why add it to
Java when you've already got the power of true object-orientation?
My answer? The C++ migrants couldn't figure out how to do things
the "right" way and demanded the crutches with which they were
familiar...
I'm not trying to start a flame war here, people! I'm merely noting
that there seems to be a lot of C++ pollution of Java taking place for
dubious benefit to most practitioners (unless they come from a C++
background).

ps. Read this out for me in plain-text:
void (*signal(int signum, void (*handler)(int)))(int);
[extract from man page for signal(2)]
Now honestly tell me that you can discern, at a glance, the
arguments, method arguments, and return type...
 
R

Roger Levy

Sudsy said:
Roger,
Here's my problem: if I define a class or interface appropriately, I
don't NEED these artifical constructs. Let's be honest with the genesis
of prototypes: they evolved as a convenience for C++ programmers. It was
so they wouldn't need to code multiple methods which only differed in
the passed arguments and the returned type.
Am I wrong? Here's a quote from "Practical C++" (ISBN 0-7897-2144-9):
"Templates provide an incredible amount of power for C++ programmers,
allowing you to write generic code that will work with multiple data
types. In abstract terms, templates are parameterized types. A template
uses the parameter or parameters sent to it to define a new data type,
called a specialization of the template, at compile time."
Given that C++ is a pre-processing veneer applied to "standard" C,
I can understand the convenience of the short-cut. But why add it to
Java when you've already got the power of true object-orientation?

I don't program in C++, so I can't argue with you about C++. But
parameterized types are a much broader idea, and certainly aren't
unique to C++. Look at O'Caml, for instance. Parameterized types can
save you a lot of time in specialized-method coding, and mistakes in
the form of casting errors. And their benefits weren't available in
Java until now.
My answer? The C++ migrants couldn't figure out how to do things
the "right" way and demanded the crutches with which they were
familiar...
I'm not trying to start a flame war here, people! I'm merely noting
that there seems to be a lot of C++ pollution of Java taking place for
dubious benefit to most practitioners (unless they come from a C++
background).

If you don't want to deal with generics, just don't use them. Java
1.5 works just fine if you never do.
ps. Read this out for me in plain-text:
void (*signal(int signum, void (*handler)(int)))(int);
[extract from man page for signal(2)]
Now honestly tell me that you can discern, at a glance, the
arguments, method arguments, and return type...

I can't, but again I've never programmed in C++.

Cheers,

Roger
 
L

Larry Barowski

Sudsy said:
Roger,
Here's my problem: if I define a class or interface appropriately, I
don't NEED these artifical constructs.

Not if you want to use the class in a general-purpose framework
(as by implementing Comparable), and want zero risk of runtime
class cast exceptions. Moving potential bugs from runtime to
compile time is a huge advantage in a non-trivial project.
 
L

Larry Barowski

Roger Levy said:
It appears that the problem with my version is that although we have
stipulated that the type of x extends Comparable<T1A super T1> and the
type of s.x extends Comparable<T1B super T1> for some T1A and T1B, we
have no guarantee that the type of s.x extends T1A. This seems to me
like a shortcoming of the syntax of generics for Java 1.5, what does
anyone else think?

By "my version", do you mean if you had done:
public class Singleton<T1 extends Comparable<? super T1>> implements
Comparable<Singleton<?>>>
In that case there would be no required relation between "T2"
and T1 at all.

I don't think more generic bounds syntax would help
in your case. The bounds I gave above are about as
complex as the English language description of the
required type restrictions. Anything more concise than
that would be obfuscation.
 
L

Larry Barowski

Jesper Nordenberg said:
(e-mail address removed) (Roger Levy) wrote in message

If I understand correctly you want:

public class Singleton<T1 extends Comparable<T2>> implements
Comparable<Singleton<? extends T2>> {

where T2 is automatically inferred by the compiler. This is not
supported by the compiler though, so I don't think you can solve your
problem without introducing new type parameters to the Singleton class
which you probably don't want to do.

Right, there is no solution if you want to use "x.compareTo(s.x)".
Using "s.x.compareTo(x)" instead leads to an obvious answer,
since then "T2" can be specified in terms of T1.
 
J

Jesper Nordenberg

It appears that the problem with my version is that although we have
stipulated that the type of x extends Comparable<T1A super T1> and the
type of s.x extends Comparable<T1B super T1> for some T1A and T1B, we
have no guarantee that the type of s.x extends T1A. This seems to me
like a shortcoming of the syntax of generics for Java 1.5, what does
anyone else think?

I would like to have the possibility to introduce named types that are
not type parameters of the parameterized class. For example:

class A<T extends B<U super T>> {
private U value;
}

I don't see why this shouldn't be allowed.

/Jesper Nordenberg
 
T

Thomas Weidenfeller

Roger said:
And their benefits weren't available in
Java until now.

There is a price to pay for this benefit. The question is, is the price
worth the benefit. And here is where opinions are different. And will
probably remain different forever.

My position, based on previous years of heavy C++ programming, is also
that generics should better not have been added to Java. Especially, the
choice of using a syntax similar to the incredibly brain dead C++
template syntax was the worst possible one to make. I know generics are
not templates, but when I already now see attempts to come up with the
most mind-twisting, ugly, hard to read ways of using generics, it is my
opinion, that Java has touched an area it should better not have touched
at all.

I was one of the great design ideas of Java to skip the obscure parts of
C/C++ (no preprocessor, no operator overloading, no pointers, etc.).
This idea has been violated. Part of the beauty and consistency of the
language has been destroyed. I would bet that it will just take a few
more Java releases, and we will see operator overloading, too.

If the trend continues, Java will end up as a "C++ with garbage
collection", just like C++ started as "C with classes". And it is not
unlikely that at this point some joker will add delete() and pointers to
the language, just for good measures, and because an other language has
this, too. At some point someone will start the Java equivalent of the
IOCCC.
If you don't want to deal with generics, just don't use them. Java
1.5 works just fine if you never do.

This is not the way to go. They are now in the language, and they won't
go away. And since people start to use them (in the most strange ways
possible of course), any serious programmer will sooner or later have to
deal with them. At least in 3p libraries, and the Java API. There is no
way around to learn them.
I can't, but again I've never programmed in C++.

That was an ANSI C example. But I can tell you, even many C or C++
programmers can't decipher this at once. (The trick is to read it from
inside-out, and to get all the meaning and precedence of all the
brackets right). It is not uncommon for C programmers to use a short
program like cdecl to decipher or construct such statements.

It is sad to see that Java has made a step in a similar direction.

/Thomas
 
J

Jesper Nordenberg

Sudsy said:
Am I wrong? Here's a quote from "Practical C++" (ISBN 0-7897-2144-9):
"Templates provide an incredible amount of power for C++ programmers,
allowing you to write generic code that will work with multiple data
types. In abstract terms, templates are parameterized types. A template
uses the parameter or parameters sent to it to define a new data type,
called a specialization of the template, at compile time."
Given that C++ is a pre-processing veneer applied to "standard" C,
I can understand the convenience of the short-cut. But why add it to
Java when you've already got the power of true object-orientation?

As others have noted developers opinions about generic types are very
subjective. Some feel they make the language harder to read and
because of that they should never have been added. Personally I agree
that they make the language harder to read, but the benefits are far
greater than any readablity issues. I like C++ templates. I didn't
choose Java to avoid C++ templates, I choose it because there it has
other benefits over C++.

About the argument that generic types are unnecessary in a OO language
like Java, I would say the contrary: Java will become more object
oriented with the addition of generic types. For example, instead of
looping over collections many will instead use predicates and closure
objects which allows for much more concise code constructs with less
room for bugs. This is something Smalltalk, Ruby etc. developers have
been using for a long time. One of the big obstructions for using this
so far is the unsafe casting that's was necessary before generic types
was added.

/Jesper Nordenberg
 
S

Sudsy

Larry said:
Not if you want to use the class in a general-purpose framework
(as by implementing Comparable), and want zero risk of runtime
class cast exceptions. Moving potential bugs from runtime to
compile time is a huge advantage in a non-trivial project.
-----------

So everything written in Java before version 1.5 is trivial? Codswallop!
I've developed large, "non-trivial" systems in Java for a number of years
and never found myself saying "darn, I wish I had generics!".
I note that some defenders of generics are wont to cite other languages
(even Smalltalk) as justification. My point was/is that Java is not the
same as other languages. It shouldn't be expected to morph simply because
some people miss certain features available in those other languages. It
would be like me demanding that Java incorporate a Working Storage Section
so that I can migrate my COBOL experience more comfortably.
Bonus points to Thomas Weidenfeller for his keen observation regarding
operator overloading!
 
M

Michael Borgwardt

That's neither stated nor implied in his statement.
I've developed large, "non-trivial" systems in Java for a number of years
and never found myself saying "darn, I wish I had generics!".

Really? You've never used collections and wished that you didn't have to
do all that casting?
 
R

Roger Levy

Larry Barowski said:
By "my version", do you mean if you had done:
public class Singleton<T1 extends Comparable<? super T1>> implements
Comparable<Singleton<?>>>
In that case there would be no required relation between "T2"
and T1 at all.

Sorry, my reference wasn't clear at all. I had originally written
(privately, not in my post) the same class class declaration and
method signature that you had, but in the method body I'd used

public int compareTo(Singleton<? extends Comparable<? super
T1>> s) {
return x.compareTo(s.x);
}
I don't think more generic bounds syntax would help
in your case. The bounds I gave above are about as
complex as the English language description of the
required type restrictions. Anything more concise than
that would be obfuscation.

Hmm...let's compare the generics syntax for method signatures and
class declarations. In a method signature, you can declare and place
constraints on type variables that never occur in the method body, and
that never need to be specified by the API client. This makes code
like the following possible:

public static <T extends Comparable<? super T>, T1 extends T, T2
extends T> int compare(T1 x1, T2 x2) {
return x1.compareTo(x2);
}

public static void main(String[] args) {
Date x1 = new Date(1);
Timestamp x2 = new Timestamp(3);
int i = compare(x1,x2);
}

IMHO, the type variable declaration in this static compare method is
extremely clear -- the two argument types must have a common supertype
that is Comparable with itself. Note that the type variable T exists
solely to specify the constraints on the common supertype. It never
appears in the method body, and the API client never needs to worry
about it.

As far as I can tell, there is no way to do something analogous in a
class declaration, because each type variable declared must be
specified by the client upon type declaration. What we'd really want,
as Jesper pointed out, is something that allows the introduction of
new type variables in the class declaration that do not need to be
specified by the API client at type declaration. This could be
something like what I originally wrote:

public class Singleton<T1 extends Comparable<? super T1>> implements
Comparable<Singleton<T2>> {
T1 x;

public int compareTo(Singleton<T2> s) {
return x.compareTo(s.x);
}
}

or something like what Jesper wrote:

public class Singleton<T1 extends Comparable<T2>> implements
Comparable<Singleton<? extends T2>> { ... }


I appreciate all the input on my problem -- I understand the issues
much better now!

Cheers,

Roger
 
L

Larry Barowski

Roger Levy said:
Hmm...let's compare the generics syntax for method signatures and
class declarations. In a method signature, you can declare and place
constraints on type variables that never occur in the method body, and
that never need to be specified by the API client. This makes code
like the following possible:

public static <T extends Comparable<? super T>, T1 extends T, T2
extends T> int compare(T1 x1, T2 x2) {
return x1.compareTo(x2);
}

...
As far as I can tell, there is no way to do something analogous in a
class declaration

Ah, I see your point. Something like that would add a lot more power
to the bounds.
 
L

Larry Barowski

Michael Borgwardt said:
That's neither stated nor implied in his statement.

Right, what is implied is that in a trivial application, "surprise"
ClassCastExceptions are generally not a concern, since
reasonable testing and code review are likely to catch all such
bugs.
Really? You've never used collections and wished that you didn't have to
do all that casting?

More importantly, in my opinion: you've never received a bug
report or crash report due to a bad cast in the release version of
a product?
 

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

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,736
Latest member
AdolphBig6

Latest Threads

Top