I have followed the progress of JSR-14 quite closely. In my opinion, given the constraint of backward compatibility with all that code out there, Sun's engineers have done a remarkably good job.There is scope for addressing some (or even all) of the problems in future revisions.

At one point the proposal did extend type safety to generic arrays, but the language concepts introduced to manage that left many bemused. So the the simpler concept of wild cards was invented, and unfortunately the question of arrays had to be put off for future work.

Most commentators seem to have missed the fact that generics does bring one potential performance improvement --- covariant returns. Covariant returns are not just a compile time transformation; in the JVM the method signature has always included the return type.

Most developers will simply use generic classes designed by others (mostly collections). This should cause few problems and have many benefits in terms of more comprehensible code. Developers implementing their own collections can just use the provided examples as a 'template' and should also have little difficulty. That leaves a very small number who need to investigate the shady corners of generics; well they will just have to get learning.

Those who think Java generics in j2se5 should have gone much further are simply dreaming. I think the current change is probably about as much as the Java community as a whole is able to accept (and there are quite a few who think it is a step too far as it is). OK, so the refuseniks and luddites are always with us (more so as a number of Java fans are escapees from C++ template and overloading nightmares).

I have followed the progress of JSR-14 quite closely. In my opinion, given the constraint of backward compatibility with all that code out there, Sun's engineers have done a remarkably good job.

Care to highlight any particular examples? I'm still confused by the fact that 1.5 has NO "-source 1.5 -target 1.4" combination - it seems that on the one hand we're told generics is this way "to provide backward compatiblity" yet the compiler itself refuses to allow you to compile backwards-compatible code !!!

If you can't run the classfiles on older VM's, what is the point of making the changes compiler-only

We have this situation repeatedly appearing where people have compiled on 1.5 and posted their game on this board and it just fails to run on most people's machines because it's default -target 1.5 and has produced non-usable classfiles.

Quote

There is scope for addressing some (or even all) of the problems in future revisions.

c.f. the long debate 6 months back about whether JCP/Sun would ever take advantage of that possibility, e.g. by changing the bytecode in future to reflect the new language syntax. ISTR there wasn't much cause for hope that it would actually happen.

If there are some public comments about anyone's intent to address these concerns in future I'd love to see them (where "anyone" means someone with enough clout to matter - e.g. a large corporate JCP member, or Sun staff, etc).

But...it leaves me wondering why such major changes (syntax changes) were pushed through with outstanding problems - is it just me, or does this mark a major change in java's direction? (nb: there has been much talk from Sun about how 1.5/5 marks a major change in direction, c.f. their new release strategies, but they don't seem to have said much about this aspect, the seeming relaxation of the determination not to make large changes without very good reason)

Care to highlight any particular examples? I'm still confused by the fact that 1.5 has NO "-source 1.5 -target 1.4" combination - it seems that on the one hand we're told generics is this way "to provide backward compatiblity" yet the compiler itself refuses to allow you to compile backwards-compatible code !!!

That is a different form of backward compatibility. The constraint was that old code would run on the new JVM, not that new code would run on old JVMs. In practice the generics stuff is almost able to run on old JVMs (see Toby Ryelt's tool). It is the other language changes (enums, enhanced for loops) that don't work well (or at all) on older VMs. They didn't want to subdivide the source 1.5 option so that you could say "source 1.5 except for enum, for" and target 1.4. In other words the source option is an all or nothing choice. The bits of generics which don't work on older JVM are obtaining reflective access to generic information about a class (note you can't obtain the actual Type values for a particular instance).

Quote

If you can't run the classfiles on older VM's, what is the point of making the changes compiler-only

One point of minimising the JVM changes is that other JVM writers can easily bring their JVM from 1.4 to 1.5 level.

Quote

machines because it's default -target 1.5 and has

Similar problems have occured with several previous major releases.

Quote

aspect, the seeming relaxation of the determination not to make large changes without very good reason)

I think the maintenance and clarity advantages of generics do constitute a very good reason.

Why does java.util.Properties extend Hashtable<Object, Object> and not Hashtable<String, String> as you might expect? Well it seems that some people put objects in to Properties which aren't String's --- there are apparently examples of this within the core libraries.

One point of minimising the JVM changes is that other JVM writers can easily bring their JVM from 1.4 to 1.5 level.

Sure, but that's one of things I lump into "political reasons" - it's not for end-users and it's not for technical superiority (although indirectly it can affect both - which is often true of political reasons).

Quote

Similar problems have occured with several previous major releases.

I remember them happening during betas, and then being "fixed" in time for release? My memories back beyond about 1.3 are vague because until then I always upgraded automatically (so many critical bugfixes!) and it seemed almost everyone else did too.

Quote

I think the maintenance and clarity advantages of generics do constitute a very good reason.

But it's all relative...for instance, it seems to me that structs would provide greater advantage in more situations with less change to the language (syntax) - yet they seem to be held back largely because they require "too much" of a change. (this may be unfair, it may be only true of non-sun staff, but I'm just laying my thoughts on the table here - this is how it *seems* to me).

And other things that would have a much wider and greater beneficial effect on java - for instance true (or even semi-true) contracts. Or aspects...

Not that I'm saying "we should have ALL of these" but they are all things that people have been clamouring for for ages, have good reasons for needing, and every single one of them seems considerably more useful than generics and to require considerably less change to the existing java language! And all of them have reference implementations of one sort or another that are quite stable (for reference implementations) with people offering to donate these references as a base for Sun or JCP to build an better implementation on top of.

IMHO, this is a large part of why it leaves a sour taste in the mouths of many java developers - there's a sense that the users of the platform are being screwed over / left out in the cold / manipulated by "the powers that be" with "improvements" that few want whilst being denied much more powerful and useful improvements with less reasoning.

Anyway, I'm still wavering on this whole topic - hence starting the thread. I'm just keen to find out what other people think and to expose myself to some wildly different opinions on this . But I admit the weight of evidence has me leaning towards "== bad for java".

Generics is something that has been hanging around as unfinished business for a long time --- far longer than many of the other changes you suggest (since the very genesis of Java in fact). Politically of course there is the fact that the C# version of generics has also appeared (and this doubtless was the inspiration for some of the other changes).

Static type safety without generics is something of a half baked cake. Nevertheless pragmatically many will be happy without it (never know what they are missing?). Language theologists (Gilad Bracha), on the other hand, strongly feel the need to complete the job. <fx: insert suitable Monty Python reference here>

In his original RFE for structs, Cas has conflated two issues (which in my opinion should be separate): his need for objects that efficiently map directly to external structures, and a more general desire for lightweight classes. There is as yet no real consensus on how these two issues should be resolved.

Note that when extending C# for generics, Microsoft could not simply redefine the existing interfaces (as has been done in Java), but instead has to create new interfaces and classes. This means that you can only use those new generic collections with new code (or have to use wrappers of some kind). Think about the 3rd party libraries you use such as JDBC drivers. If generics worked like it does in C#, you wouldn't be able to use generics with these until your supplier had caught up. This may matter less in the Windows world because Microsoft supply so much themselves. In Java, though, such a restriction would probably set back the adoption of generics by several more years.

Nah... you are allowed to put anything into it. You won't be able to save it to a properties file anymore - that's the only price you had to pay for doing so.

Well, yes. But I get the feeling that you were never intended to be able to do that - why would they write a Properties object that half allows non-String entries, and half blows up entirely with non-String entries?

No, IMHO it's a bug, and one which can now very easily be fixed. So some people's code will fail to compile - so what? They shouldn't have used it in the first place. If I depend on non-core packages, it's my fault if they go away in-between releases. If I exploit a bug, it's my fault if my application doesn't work with later JREs.

One of the biggest problems I see with Java today is the increasing amount of crud that's building up. All the old stuff is being kept along with the new, giving us Hashtable and HashMap, Vector and ArrayList, frame.show() and frame.setVisible(true). I'm all for removing the old crusty APIs that no one should be using anymore, and making Java sleek again.

I was rather hoping that Java would undergo a backwards-compatibility break and cleanup when they finally reached 2.0, but since 1.2 became Java2, and 1.5 became the 5.0 version of Java2, all version numbers have gone out the window. There's no obvious place that they can plan a complete re-work anymore.

You say that they may decide to make "raw" Generics illegal - that's not going to happen unless Sun really change policy in this area.

Think about the 3rd party libraries you use such as JDBC drivers. If generics worked like it does in C#, you wouldn't be able to use generics with these until your supplier had caught up....such a restriction would probably set back the adoption of generics by several more years.

Interesting idea. In the use-cases I have before me you can't until the supplier catches up anyway, because generics is pointless in my code until the library supplier alters their code to use the new syntax.

Presumably...it's just a question of "source". Where a library is the source of the data, you can't use generics until the supplier "catches up", but where the library is a processor of your data you can use it right away?

No. JDBC is specified largely in terms of interfaces which are updated in j2se5, yet it will happily load and use drivers that were compiled using j2se1.4 or even earlier.Because generics information is erased in the byte code, all you need to be able to use it that the interface (or abstract classes) that you use have been rewritten in terms of generics, while ensuring that the erased version is unchanged. Hence I am also able to use old collection classes via the new generic interfaces even if those implementations haven't been recompiled.

Presumably...it's just a question of "source". Where a library is the source of the data, you can't use generics until the supplier "catches up", but where the library is a processor of your data you can use it right away?

Well, you can easily write a conversion layer on top of whatever API it is to convert the old-style Collections into new-style properly-typed Collections. Then you'll get all the benefits of compile-time type safety in your own code, without the vendor making any changes at all.

Regarding the library as a processor of your data - sort of. Javac will issue a warning when you pass a generic Collection to a non-generic interface, as the consumer could bugger it up causing your own code to fail. But it'll still let you do it with that caveat.

I still can't think of a good reason for type erasure. It didn't need to be backwards compatible at all! 1.5 code won't run on a 1.4 VM anyway! Gah! They could have just introduced a new classfile format, bumped the version number and put in a few more bytecodes...

...of course, the syntax doesn't preclude this actually happening in a future release. We could have arrays of generics, and templated code, etc. etc. So maybe they'll be enhancing the VM one day to do what we want.

...of course, the syntax doesn't preclude this actually happening in a future release. We could have arrays of generics, and templated code, etc. etc. So maybe they'll be enhancing the VM one day to do what we want.

That is my hope --- that the current state is a necessary stepping stone to a 'true' generics system. If migration to generics was too painful it just wouldn't happen.

I still can't think of a good reason for type erasure. It didn't need to be backwards compatible at all! 1.5 code won't run on a 1.4 VM anyway! Gah! They could have just introduced a new classfile format, bumped the version number and put in a few more bytecodes...

As far as I understand the reason for type erasure:

You have library A which depends on library B. Library A is 1.4 based, library B is also 1.4 based. Now, library B gets some bugfixes and at the same time they decide to use 1.5 generics in their API. You of course will need 1.5 to run this library. Trick is, that you don't care about B - you care about A. A is still 1.4 and should work without any recompilation with new version of library B, as long as only change is generification(?) of signatures. They had to come up with way to make sure that m(List) call compiled under 1.4 will call m(List<something>) method under 1.5, without recompilation.

If I'm right, than it could be fixed by generating m(List) bridge method under 1.5 (similar to way covariance is done now), which would do neccessary operations to convert 1.4 List to 1.5 List<something>. Don't know how exactly it would have to be done (this would depend on exact implementation of generics-done-right).

If I'm right, than it could be fixed by generating m(List) bridge method under 1.5 (similar to way covariance is done now), which would do neccessary operations to convert 1.4 List to 1.5 List<something>. Don't know how exactly it would have to be done (this would depend on exact implementation of generics-done-right).

What happens if library A implements a List which it passes to B which is now expected a List<Sometype>? Without erasure you would have to supplement the methods (and fields) on A's list with the extra generic signatures and additional type information. Except that you don't know what the type required is (if your lucky it will be encoded in the field name or the documentation).You can't automatically add type information to existing code; erasure avoids the issue by making all code equal at runtime.Once generics is in widespread use, the information will be available at least in the source code (and perhaps in the byte code as attributes which are ignored by the current runtimes). Then it may be possible to move to retaining the type at runtime with relatively little pain.

Criminy, anybody would think that refactoring code is expensive or difficult! It's possible in just a few days to completely refactor a multi-thousand class application. It's just fear and laziness holding people back and an inability to cope with actually having to do some work.

Interesting conversation, didn't really want to post and get shot down but anyway.. I dislike generics for probably what can be considered a crappy reason. : They're easy to misuse.

How many times have you actually got a list of things exposes to the outside user of class that is actually just a list of objects? Normally its a list of objects representing something, books on a shelf or players in a game. So, having to put a class in place called Shelf or at worst PlayerList is rather nice. Whats more how many times have I come across C++ code (which I do for a living) where someone has happily used a templated class for something because "it'll be quicker". Later they realise that their list of objects actually needs to do something that lists don't normally do. Now, do they run round their code changing types to some new wrapper class or do they just knock in a function that takes their templated class as a parameter and does the job.

Whats more, how many additional methods do you pick up when you're exposing your list in this wonderfully convienient method.

In general, Generics just seem to be to easy to get into sloppy coding practice which leads to a lack of refactoring points and a whole set of unexpected client calls...

At this point, feel free to shoot down.. let me start you off: But thats not the languages problem that the programmers being sloppy, fix them.. yeah sure. One of the nicest things I've found about Java is that it tends even terrible programmers in the correct direction. Generic move us closer to the "power" of C/C++ and closer to the misuse and the crapness of the source I get to work with everyday.

Kev

EDIT: Just read through, I'm not in the best of moods am I? Take with a pinch of the proverbial.

Criminy, anybody would think that refactoring code is expensive or difficult!

It can be impossible if the code is not yours to refactor (especially if it is 3rd party code supplied without source). If you had to wait for all the 3rd party libraries to be updated before you could use generics, then it could be a very long wait.

Seeing as Java is a well-understood bytecode format it shouldn't have been outside the realms of possibility to have provided a JAR converter in the JDK which added generic type information to all the classes and upgraded them to the new classfile format.

What happens if library A implements a List which it passes to B which is now expected a List<Sometype>? Without erasure you would have to supplement the methods (and fields) on A's list with the extra generic signatures and additional type information. Except that you don't know what the type required is (if your lucky it will be encoded in the field name or the documentation).

This would be solved by bridge methods. B would have syntetic method not visible for normal programmer, which would implement something like:

1 2 3

voidmethod(Listl) {this.method(cast_to(List<Something>,l));}

Now, the question is, how to implement specialized_instance cast_to(specialized_type, erased_instance). Please note that all that types are known at compile time of B, so any amount of needed code can be inserted there. Probably something like

This would work only for collections with addAll - but I think that collections are most important thing here. As an alternative, you could require generic classes to implement <specialize_cast> method, which would return specialized instance of given type with data copied from erased type - this would work for all possible classes (with collections inheriting implementation from AbstractMap/AbstractList)

Of course, if caller has passed non-Something element inside array, there will be a runtime exception somewhere in code - but it would probably happen anyway, if method was expecting list of Somethings in previous version of library.

Edit:Ok, I have reread your issue and now I see that problem is with implementing list, not just with passing it. I will think about it...

Edit:

In case of 1.4 code implementing generic interfaces, cast_to would have to probably create wrapper, which would implement target specialization, while delegating all calls to backing 1.4 implementation. Which could of course lead to some inconsistencies like

1

Listm(Listlist) { returnlist; }

changed in 1.5 to

1

List<String> m(List<String> list) { returnlist; }

which would cause following 1.4 code to behave in different way

1

System.out.println(list == PackageB.m(list));

Solution for that would be to unwrap such proxies on return to 1.4 code (done of course by jvm when linking 1.4 classes to 1.5 classes).

java-gaming.org is not responsible for the content posted by its members, including references to external websites,
and other references that may or may not have a relation with our primarily
gaming and game production oriented community.
inquiries and complaints can be sent via email to the info‑account of the
company managing the website of java‑gaming.org