Why Generics?

  • Thread starter David Blickstein
  • Start date
C

Chris Uppal

Thomas said:
Here is a quick comment of mine in comp.object regarding you smalltalk
guys, and what followed is probably one of the funniest posts I've ever
read by a character named Phlip (a frequent contributor). The funny part
is paragraph #5.
http://groups-beta.google.com/group/comp.programming/msg/b492c72ae1821e4b?hl=en

I'm sorry, I but can't see any humour in this. Granted that Phlip was a little
tactless to reveal the Unpeakable Truth, but then what can you expect from a
guy with only one 'I' in his name...

-- chris
 
T

Tor Iver Wilhelmsen

Chris Uppal said:
What happens if you use features like enums or auto-boxing which rely on
elements of the platform library that were added in 1.5 ?

Enums do (relying on java.util.Enum), but autoboxing is just compiler
sugar for using the immutable wrappers.
 
M

Mike Schilling

Chris Uppal said:
Fair point.

Though you /could/ make it throw a checked NullCastException or something
like
that.

I suppose, but what would a catch block for NullCastException do?

Just out of curiosity, would you like to see some sort of compile-time
null
check added to the type system ?

You've lost me, because I thought that's what I was proposing :) If you're
asking if I think it's a good idea, yes, though I can't see adding it to
Java now without insuperable compatibility issues.
 
J

John McGrath

What happens if you use features like enums or auto-boxing which
rely on elements of the platform library that were added in 1.5 ?

The code example I posted uses auto-boxing in the list.add() call:

List<Integer> list,
:

for ( int value : values ) {
list.add( value );
}

The code generated for enums works on JDK 1.4, but on JDK 1.3 and earlier,
it gets a verify error loading the enum class itself. If you turn off
verification, it works.

The following code runs properly:

public class EnumTest {
enum Sport {
BASKETBALL, BASEBALL, FOOTBALL, RUGBY;
public Sport next() {
return values()[ (ordinal()+1) % values().length ];
}
};

public static void main( String[] args ) {
Sport sport = Sport.RUGBY;
printSport1( sport );
printSport2( sport.next() );
}

private static void printSport1( Sport sport ) {
System.out.println( "sport1 = " + sport );
}

private static void printSport2( Sport sport ) {
System.out.print( "sport2 = " );

switch ( sport ) {
case BASKETBALL:
System.out.println( "BASKETBALL" );
break;
case BASEBALL:
System.out.println( "BASEBALL" );
break;
case FOOTBALL:
System.out.println( "FOOTBALL" );
break;
case RUGBY:
System.out.println( "RUGBY" );
break;
default:
System.out.println( "Unknown" );
break;
}
}
}
 
J

John McGrath

Enums do (relying on java.util.Enum), but autoboxing is just compiler
sugar for using the immutable wrappers.

Actually, the generated code only extends java.lang.Enum when targeting
JDK 1.5. When targeting earlier JDKs, it extends Object and implements
Serializable and Comparable.

Similarly, for JDK 1.5 it uses StringBuilder to implement the String "+"
operator, but for earlier JDKs, it uses StringBuffer.
 
A

Adam P. Jenkins

John said:
I'd like to be able to say something like:
javac -source 1.5 -target 1.2 *.java
but the compiler won't let me.


You can do that with JBuilder 2005. Here is a test program that I
compiled with JBuilder and ran under JRE 1.2.

import java.util.List;
import java.util.ArrayList;
import java.util.Collections;

public class Test
{
public static void main( String[] args ) {
List<Integer> list = new ArrayList<Integer> ();
[Snipped more code using generics, autoboxing, foreach]

I've been doing the same thing just using ant and the open source
Retroweaver tool. Retroweaver allows my project, which uses generics,
autoboxing, foreach, and enums to run under JVM 1.4. Retroweaver's
homepage is here: http://retroweaver.sourceforge.net.
 
O

opalpa

I write lines of code and revise them.. Without generics, often goes:

ArrayList stuffed= new ArrayList();
....
MyStuff stuff = (MyStuff) it.next();
stuff.yo();


with them

ArrayList<MyStuff> stuffed = new ArrayList();
....
for (MyStuff s: stuffed) {

}

For reading sometimes generics code goes like this:

ArrayList<MyStuff> stuffed = new ArrayList();
for (Iterator<MyStuff> it=stuffed.iterator(); it.hasNext(); ) {
... code ...
it.next().yo();
... code;
}

compared to:

((MyStuff) it.next()).yo();

Yeah, more letters, right, you reaally sure mind typing, ok, but like
the info is values that seem relevant to the operation (IMHO).

As for javadoc, method summary is to return to a state without generics
notation. Generics notation will be available in method details
section along with non-generics notation.

Problen Eric Sosman notes does not arise.
 
T

Thomas G. Marshall

Chris Uppal coughed up:

Aw c'mon, yes you do.

Granted that Phlip
was a little tactless to reveal the Unpeakable Truth, but then what
can you expect from a guy with only one 'I' in his name...

Smalltalk has been at the top of my list of things-to-investigate for a very
long time. The sheer number of times that it is mentioned with glowing
accolades by the purists should be enough to make anyone jump to two
extremes, with nothing in the middle: 1. Be very very interested in it, 2.
run from it screaming with arms in the air.

I'm historically leery of what purists have to say, but I have built a very
firm appreciation for them since bopping around in comp.object.
 
C

Chris Uppal

John said:
The code example I posted uses auto-boxing in the list.add() call:

Sorry, I missed that (didn't read the code to be honest -- I very rarely /do/
read code in ng postings).

Thanks.

-- chris
 
C

Chris Uppal

Mike Schilling wrote:

[me]
I suppose, but what would a catch block for NullCastException do?

That's where null-case code would go.

The advantage of doing the null-checking in that way would be that the
nullable/non-nullable distinction could be handled in the language (so that
javac "knew" whether a given reference could possibly be null) without
requiring relatively intricate extensions to the flow analysis that it is
required to perform. I.e. without special syntax like "ifnull" or sematic
additions like requiring the compiler to recognise "if (aRev == null)" as a
special case. Admittedly, it's kinda kludgy....

You've lost me, because I thought that's what I was proposing :) If
you're asking if I think it's a good idea, yes, though I can't see adding
it to Java now without insuperable compatibility issues.

I didn't know if you were thinking of it as something desirable (if not
necessarily feasible now), or were more interested in it as a design
experiment. (I'm more in the latter camp, myself -- though I wouldn't say that
it's a bad idea /if/ you allow that static declarative typing is a good idea in
the first place.)

Perhaps it could be introduced in a non-breaking way. First off, it would
obviously have to be a compile-time only thing, like generics. Secondly it
would have to "play nicely" with older third party libraries that didn't use
it. Ideally, it would not prohibit new code from running on older JVMs though
that is presumably not a necessary condition (compare Sun's implementation of
generics which also refuses to target older editions of the platform).

Lets say that there's a new flag that can be added to classes along the lines
of "strictfp". If a class is flagged with "strictnull" (or perhaps a special
flag is passed to the compiler which causes it to assume strictnull by default
for the target classes), then it will interpret the declaration
<sometype> var;
as meaning the non-nullable variant of <sometype>. Special syntax is required
to mark specific types as nullable/not-nullable. I rather like the idea of
using a generics-style syntax myself with Nullable<sometype> being the nullable
equivalent of a given type (which might already have been nullable), and
NotNullable<sometype> as the not nullable equivalent of a given type (which
might already have been not-nullable). The "strictnull" flag is then telling
the compiler whether to assume Nullable<> or NotNullable<> by default for
declarations in that class.

Some way of expressing tell-tests is then needed, as discussed earlier. One
problem with using the NullCastException approach is that that would require an
new checkable exception in the standard hierarchy. That would make it
impossible to run new code on an old JVM. Also methods that allowed
NullCastExeption to leak could not normally be called /from/ old code, since
they wouldn't have the relevant handlers. That could be seen as an advantage,
though.

Lastly, we need some way of recording what type-discipline is used for a given
class in the classfile. But that's pretty trivial since it can be handled as
an upward compatible extension to the format in much the same way as generics
are. The nullable/not-nullable qualifiers on type references would be "erased"
in a similar way to generics, but would be recorded in a separate part of the
classfile, where newer compilers would see it and could compile accordingly.
Older compilers would ignore it (as would the JVM itself) and so the underlying
semantics would not change, so NullPointerExceptions would still be possible as
far as the underling implementation knows.

Hmm... I'm starting to think that it's doable...

-- chris
 
C

Chris Uppal

Thomas said:
Aw c'mon, yes you do.

No. Every word in Phlip's post is absolutely true.

(Oh, all right, yes it is funny...)


Smalltalk has been at the top of my list of things-to-investigate for a
very long time. The sheer number of times that it is mentioned with
glowing accolades by the purists should be enough to make anyone jump to
two
extremes, with nothing in the middle: 1. Be very very interested in it,
2.
run from it screaming with arms in the air.

Yes, I too can only take so many people telling me how wonderful <x> is before
I develop a deep aversion to <x>.

-- chris
 
T

Thomas G. Marshall

Chris Uppal coughed up:
No. Every word in Phlip's post is absolutely true.

(Oh, all right, yes it is funny...)




Yes, I too can only take so many people telling me how wonderful <x>
is before I develop a deep aversion to <x>.


Hope noone expounds upon the virtures of sex or breathing to you.
 
D

Dale King

John said:
I don't exactly consider that a "risk". I'm not sure I even fully agree
that it's true. The rules and forms for generics are in fact fairly
simple (I claim), though they can be combined in complex ways. They
nevertheless do make for a few more things to learn.

I would say that when you start getting into upper and lower bounds on
wildcards it is complex (I still haven't grokked it all myself). But for
most users of generics (using the collection classes) that doesn't even
really come up. I agree that calling that a "risk" is a bit of a stretch.
 
D

Dale King

Chris said:
Remember that you must always fail as early as possible! Generics
turn Runtime Errors (class cast exceptions) into compile time errors.
This
has tremendous values.

For this to have "tremendous value" then it must be the case that class
cast exceptions are being thrown in expensive-to-change code (deployed
or late in testing) on frequent basis. That is not my experience.
[...]

It greatly depends on whether or not you ship your code. Of course if
it's you who is the 'client' or someone in the next cubicle, you are
right. But sometimes its halfway around the world.


This is something of a simplification. I agree that code that has shipped
(however far it's gone physically) has a higher cost to change than code that
has not shipped. Code that has shipped to many customers has a higher cost
than code that has shipped to only a few, or even none. Etc. But what your
analysis misses is factoring in the probability of there being a problem in the
first place. If that were mathematically, exactly, zero then clearly it
doesn't matter how far the code has shipped. If the probability is low enough
then even when multiplied by the large cost of late changes, the resulting
probable cost is low.

It is not enough to say "it would be bad if it happened", you also have to ask
how likely it is to happen before you decide what preventative measures are
justified.

As others have said, class cast exceptions are so rare that many people have
never even seen one -- not even in development code (I never have) -- so the
probability of there being one in any given shipped application is very low.
Given that multiplier, it is unlikely that there is "tremendous" value to be
found in "eliminating" them. Not unless the cost of failure is absolutely
stratospheric (hundreds of human lives, say).

And in addition to factoring in how likely you are to introduce such an
error you also have to factor in the probability that it will be
undetected until it ships.

I'm not sure I can say that I have never written code that never had a
CCE (although I can't think of a specific instance), but if one were
introduced its hard to think of a credible case where that would not
easily be detected at runtime so that the odds of it getting out the
door are pretty much nil. It would be nicer to catch that at compile
time but the cost differential is almost zero.

So unless you are writing code and shipping it without ever running it
the early detection benefit of generics pales in comparison to just the
better documentation benefits.
 
D

Dale King

Chris said:
Dale King wrote:




I think it's a shame too. There was only one change in the JVM spec in 1.5,
and that isn't used by any of the new language features (it just allows a less
hacky way to translate <typename>.class expression into bytecode). I'd like to
be able to say something like:
javac -source 1.5 -target 1.2 *.java
but the compiler won't let me.

Someone once told me in this group that there was a way. It was
something like -target JSR14 (or whatever the JSR number was for
generics). I don't know if that still works, but it is not documented
anywhere that I can find.

There is also a 3rd party tool called Retroweaver that would let you do
it, but a 3rd party tool would not help the uptake of generics.
I can see some justification for this: although
the compiler could easily generate legal (for pre-1.5 platform) bytecode
sequences for the new features, some of them require support classes/methods
that are not present in earlier versions of the library (java.lang.Enum, for
instance, or java.util.Integer.valueOf(int) for autoboxing). I suppose the
idea is to keep things simple (Sun, Java, /simple/ ? Ha !) by just imposing a
blanket ban, but it seems (to me) that it is more likely to impede the takeup
of generics, etc, than anything.

Which was my point in previous conversations. It will be years before
many of the libraries you depend on will convert to generics because
they don't want to have to maintain 2 releases.
 
T

Thomas G. Marshall

Chris Uppal coughed up:
;-)

-- chris

Changing the subject line for this and (lol) removing the conversation
context was a sketchy thing to do. :) It means that this message has
landed on some browsers as a thread on its own. Yikes.



--
Unix users who vehemently argue that the "ln" command has its arguments
reversed do not understand much about the design of the utilities. "ln
arg1 arg2" sets the arguments in the same order as "mv arg1 arg2".
Existing file argument to non-existing argument. And in fact, mv
itself is implemented as a link followed by an unlink.
 
T

Thomas G. Marshall

Dale King coughed up:
Chris said:
Remember that you must always fail as early as possible! Generics
turn Runtime Errors (class cast exceptions) into compile time
errors. This
has tremendous values.

For this to have "tremendous value" then it must be the case that
class cast exceptions are being thrown in expensive-to-change code
(deployed or late in testing) on frequent basis. That is not my
experience.
[...]

It greatly depends on whether or not you ship your code. Of course
if it's you who is the 'client' or someone in the next cubicle, you
are right. But sometimes its halfway around the world.


This is something of a simplification. I agree that code that has
shipped (however far it's gone physically) has a higher cost to
change than code that has not shipped. Code that has shipped to
many customers has a higher cost than code that has shipped to only
a few, or even none. Etc. But what your analysis misses is
factoring in the probability of there being a problem in the first
place. If that were mathematically, exactly, zero then clearly it
doesn't matter how far the code has shipped. If the probability is
low enough then even when multiplied by the large cost of late
changes, the resulting probable cost is low. It is not enough to say "it
would be bad if it happened", you also
have to ask how likely it is to happen before you decide what
preventative measures are justified.

As others have said, class cast exceptions are so rare that many
people have never even seen one -- not even in development code (I
never have) -- so the probability of there being one in any given
shipped application is very low. Given that multiplier, it is
unlikely that there is "tremendous" value to be found in
"eliminating" them. Not unless the cost of failure is absolutely
stratospheric (hundreds of human lives, say).

And in addition to factoring in how likely you are to introduce such
an error you also have to factor in the probability that it will be
undetected until it ships.

I'm not sure I can say that I have never written code that never had a
CCE (although I can't think of a specific instance), but if one were
introduced its hard to think of a credible case where that would not
easily be detected at runtime so that the odds of it getting out the
door are pretty much nil. It would be nicer to catch that at compile
time but the cost differential is almost zero.

This line of reasoning is missing a critical component in order to be valid.

Even if everyone have /hardly ever/ experienced a CCE in their entire life
does not mean guarding against it is a waste of time. Why?

Because the engineers writing the code /know/ of the pending doom of the CCE
and (hopefully) code appropriately. The advantage of generics would be the
time saved from having to /worry/ and /code around/ the shortcoming.

It simply is neither conclusive, nor even implicative, that CCE's seem rare.
 
L

Lee Fesperman

Dale said:
I'm not sure I can say that I have never written code that never had a
CCE (although I can't think of a specific instance), but if one were
introduced its hard to think of a credible case where that would not
easily be detected at runtime so that the odds of it getting out the
door are pretty much nil. It would be nicer to catch that at compile
time but the cost differential is almost zero.

So unless you are writing code and shipping it without ever running it
the early detection benefit of generics pales in comparison to just the
better documentation benefits.

That's going a bit far. It could easily be in a very rarely exercised path. 100% test
coverage is nearly impossible, especially in larger systems. The resulting cost of the
undetected problem could be quite large ... losing a major sale, for instance.
 

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

Similar Threads

Generics ? 14
can this be done with generics? 32
More Generics warnings. 5
stupid generics 38
Generic generics help 7
Java generics limitations? 9
Generics and for each 12
Help on java generics 18

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top