Sam Pullara has written some interesting thoughts on 1.5 generics... compared to an autocasting approach. He walks through examples and compares their usability. You will also get a pointer to the javadocs for HashMap. Quite scary :)
In the end, what I am really worried about, is adding all of this "generics" syntax to the language? I mean, have you looked at the javadocs for HashMap lately? That is enough to intimidate virtually anyone but a C++ programmer. If they aren't careful Java will be crushed by much easier to use languages like Groovy just because the programs are about to get a lot more complicated.
public class HashMap<K,V>
implements Map<K,V>, Cloneable, Serializable
public HashMap(Map<? extends K,? extends V> m)
Read Sam's thoughts in Usability and Java 1.5 generics vs. Autocasting
Hey Sam, I think your example has chopped out the generics syntax..
Should be (hope this works for me ;) )
Map map = new HashMap<String, String>();
String value = map.get("key");
I just forget to quote them in the HTML. The page has been updated with the appropriate escaping now. What you have is a little off btw, you have to put the <String, String> on both the LHS and RHS:
Map<String, String> map = new HashMap<String, String>();
The new generics stuff is sure going to make things a lot less readable with very little benefit to the developer. My only hope is that perhaps certain types of collections (like Map<int,int>) can be heavily optimized because the need for boxing and unboxing disappears. Given how much faster the Trove collections are compared to regular SDK collections I will tolerate they hideous template syntax if the potential optimizations are realized. On this note, has anybody tested the performance of 1.5 collections?
You can't use primitive types in the declaration, so you would have to have:
And then the compiler will autobox for you, but its going to be extremely inefficient. I'm pretty sure that there won't be any interesting optimizations for this, except maybe in the VM.
You can't use primitive types in the declaration, so you would have to have:Map<Integer, Integer>And then the compiler will autobox for you, but its going to be extremely inefficient. I'm pretty sure that there won't be any interesting optimizations for this, except maybe in the VM.
Really? Well, then I like those generics even less. It's nonsensical to introduce templates and still be forced to deal with primitive types in an explicit fashion. The great thing about C++ templates is that you can write code that can deal with basic types and user defined objects without any rewrites or common base class policy. I fail to see a single benefit of Java generics. The so called type safety thing is only relevant in languages that don't have runtime type checking and incorrect casts can get you in REAL trouble (like corrupting memory). In my experience, Java casting errors are usually caught and fixed in less than a minute of debugging.
<blockquoteReally? Well, then I like those generics even less. It's nonsensical to introduce templates and still be forced to deal with primitive types in an explicit fashion. The great thing about C++ templates is that you can write code that can deal with basic types and user defined objects without any rewrites or common base class policy. I fail to see a single benefit of Java generics. The so called type safety thing is only relevant in languages that don't have runtime type checking and incorrect casts can get you in REAL trouble (like corrupting memory). In my experience, Java casting errors are usually caught and fixed in less than a minute of debugging.You're wrong in your assumptions.
A Collection with generic for Integer WILL accept primitive int values and autobox and autounbox them.
It will not accept anything that can't be autoboxed to (or is derived from) an Integer though, which is exactly how you'd think it would behave.
To me generics and autoboxing/unboxing now start to look like interesting features.
I too was wary at first and it WILL take some getting used to the new syntax but in the end it saves a lot of explicit casts that you now use only to make the compiler happy and not because they add anything for the human reader.
That will be the strength of generics. Personally I don't think it will deter people from Java, except maybe some who are unwilling to learn anything (the typical poster of questions asking people to do their homework for them) and I don't think those will be missed.
I think the generics syntax is quite simple and intuitive. What is so difficult in creating a HashMap by passing two parameters (one the key type and the other the Value type). It improves readability and correctness.
IMHO, any Java programmer would get this concept in about a couple of minutes if not less.
I think the generics syntax is quite simple and intuitive. What is so difficult in creating a HashMap by passing two parameters (one the key type and the other the Value type).
I don't think this is where the confusion will come in. Using a class will be relatively easy. Understanding that class is where it gets tricky.
For my money, I'm starting to not like Generics.
If you need type safety in a collection you could always wrap it with a typed container class. Adding such complexity to a langauge while trying to get more corporate-level programmers on-board with Java seem like opposite goals to me, Sun.
From my experience with C++ and C# with generics (mono) is that:
1. Generics vastly improves library design. When you have third-party classes with functions returning a Set or a HashMap, you simply have to refer to the documentation to figure out what the collections contain. With generics, you are in safe hands and you will get collection-type support from the intellisense feature of your favorite IDE.
2. Performance is improved - at least it can be. The reason is that casting has a runtime cost that can be eliminated. Quite important in inner loops of heavy algorithms.
... Performance is improved - at least it can be. The reason is that casting has a runtime cost that can be eliminated. Quite important in inner loops of heavy algorithms.
In Java you will not see any performance improvement; the reason is well explained by Anders Hejlsberg (lead C# architect) in http://www.artima.com/intv/generics2.html
"For example, with Java generics, you don't actually get any of the execution efficiency that I talked about, because when you compile a generic class in Java, the compiler takes away the type parameter and substitutes Object everywhere. So the compiled image for List<T> is like a List where you use the type Object everywhere. Of course, if you now try to make a List<int>, you get boxing of all the ints. So there's a bunch of overhead there. Furthermore, to keep the VM happy, the compiler actually has to insert all of the type casts you didn't write. If it's a List of Object and you're trying to treat those Objects as Customers, at some point the Objects must be cast to Customers to keep the verifier happy. And really all they're doing in their implementation is automatically inserting those type casts for you. So you get the syntactic sugar, or some of it at least, but you don't get any of the execution efficiency. So that's issue number one I have with Java's solution."
Exactly. There will be no performance improvement, it's just syntactic sugar with the added benefit of compile-time checking. I think that the compile time checking was the major goal, not performance though. Always a tradeoff...
Now, you could make the argument that having generics without performance is mostly worthless, but the stated goal of many of the 1.5 enhancements was to increase the use of Java by new developers (ie beat .Net). I hope this helps, though the issues with JavaDocs and the whole <? extends K> syntax may be more confusing than anything else.
At the least, having these changes in the language leave the door open for later additions to the underlying implementation. At some point compilers could add in optimizations that really do use ints instead of autoboxing, etc. I was always a big fan of things like the C++ Vector<byte> which used an array of ints and some fancy bitwise logic to store the values.
Now, you could make the argument that having generics without performance is mostly worthless, but the stated goal of many of the 1.5 enhancements was to increase the use of Java by new developers (ie beat .Net). I hope this helps, though the issues with JavaDocs and the whole <? extends K> syntax may be more confusing than anything else.At the least, having these changes in the language leave the door open for later additions to the underlying implementation. At some point compilers could add in optimizations that really do use ints instead of autoboxing, etc. I was always a big fan of things like the C++ Vector<byte> which used an array of ints and some fancy bitwise logic to store the values.
Do you really think that something like
public class HashMap<K,V>
implements Map<K,V>, Cloneable, Serializable
public HashMap(Map<? extends K,? extends V> m)
will help us to attract new developers? I don't think so.
Why a VB.NET developer should choose this ugly syntax (quite similar to C++ without performance benefits!) ?
Interestingly, the main problem I have with generics hasn't been mentioned at all in this thread: no typedefs.
The only way C++ managed to keep a certain amount of readability with its templates was through the use of typedefs. You could alias complex templates to a friendly name and use that friendly name everywhere (and more recently, that friendly name is now used in the error messages as well, although it took quite a while to get there).
I can only assume that typedefs were considered and then rejected by JSR 14 for a good reason, but I would love to know what it is...
I might be in the minority on this, but the documentation isn't that bad. Yes, it has the generic parameters, but what were you expecting? The portion that Sam quoted was merely the technical preamble to the documentation. The rest looks and feels like JavaDoc always has.
Compared to C++ templates, Java generics are easier to use and bring about compile time type safety in many cases where it wasn't possible before. The library has been well designed to take advantage of the feature without being too intrusive in developer written code. If you choose never to write classes that support generics directly, your 1.5 learning curve mostly consists of using the new collection classes. C# generics are supposedly going to be higher performing because of VM support, but have the exact same syntax tradeoffs as the Java version.
My beef with Java generics is that after programming in C++ for so many years I can't make them do what I want them to do. Considering all of the spooky magic that exists in the C++ template world, that's probably a good thing :-)
From reading all the comments, pro's and con's it seems that Han's first point is the reason why Generics will improve Java for newbies - not so much that they will use it, but that the libraries they use will use it.
Generics vastly improves library design. When you have third-party classes with functions returning a Set or a HashMap, you simply have to refer to the documentation to figure out what the collections contain. With generics, you are in safe hands and you will get collection-type support from the intellisense feature of your favorite IDE.
As for the performance issue, perhaps that's true, although somehow I'd take what the creator of C# writes about Java with a grain of salt. Have you ever read an article by Gosling on C#? As you can guess, C# comes off as poor imitation with many flaws.
Overall, Competition is good though. I don't think we'd be seeing all these improvements in Java without .NET.
Autocasting cannot replace generics. Autocasting is dangerous feature: what if compiler autocast something you do not intent to autocast?
Generics is wery well done in J2SE 1.5 if you consider requirements for backward compatibility (although backward compatibility is starting killing Java).
Annotations are very well done, too.
Many people bashes everything that comes from Sun. Unreadable syntax for generics and annotations? Don't think so, people will become familiar with it. And C/C++/Java/C# syntax is not ugly compared to Pascal or ADA? And what about AspectJ sytax that is extremely ugly and nobody complains about it, just because it comes from independent source.
Sun is doing good with J2SE 1.5, although they should consider new Java release without backward compatibility burden in the near future (5 years max).
Instead of punching a hole in the language that lets you fly starships through it the context lookup pattern itself should be "templatized".
Autocasting is exactly identical to what you can do now with a cast. No hole in the language. For example, if you tried to do this:
String s = new Integer(1);
It would fail at compile time, just as if you typed:
String s = (String) new Integer(1);
As for your templatization of lookups, do you have a suggestion about how to do it? If so, I would like to see one that is backwards compatible and solves the other issues. Really, I'm not saying that Autocasting is the way to go, I just think it has better properties than generics.
I agree. I think generics is an ugly solution and will keep newies (and maybe oldies) out of Java.
Sure there's a learning curve to reading generic types. But to me the real value in generics comes in adding more type safety. There's a big difference between a comment that says a collection holds a given type (which can easily drift or become wrong) and a type system that guarantees it. The 1.4 compiler doesn't even catch this error:
List l = new ArrayList();
Integer x = (Integer)l.get(0);
It's also true that you can do away with a lot of type declarations and have compilers perform "type reconstruction" (as ML does), but there are caveats.
So while I agree that scripting languages like Groovy are great for code that individuals or small groups work with, I think the Java approach of having statically declared types is the right one for larger scale software engineering. And given that you like checked exceptions, clearly you agree to some degree... :-)
The error I was referring to was
List l = new ArrayList();
System.out.println((Integer)l.get(0)); // <== HERE
I am not sure how a compiler will ever catch that. To take your example a step further
List l = new ArrayList();
System.out.println((Integer)l.remove(0)); // This should fail at compile time
System.out.println((Integer)l.remove(0)); // But this is fine
It will be an unreasonable burden on compilers to keep track of every cast that is being performed.
Off topic: I am also a C-Bridge alum (just quit a few weeks ago), wondering what you have been upto.
You're right: auto-casting won't work here. However, the generics in Java 1.5 *will* allow the compiler to catch this error. Here's the generic version:
List<Integer> l = new ArrayList<Integer>();
l.add("hi"); // <== this is a compiler error right here: you can't insert
// a string into a List of Integer!
l.add(1); // fine: Java 1.5 auto-boxes
// this is like Sam's example: the compiler knows the type from the get
Cedric: I also thought about whether adding typedefs would be a benefit here. I think it is probably a wash (more syntactic sugar but yet more complexity). As an AspectJ developer, I would really like typedefs but that's another issue...
p.s. I'll email you Alok
The need for typedefs increases proportionally to the number of nested generic classes in your type statement. ArrayList<ArrayList<SpecialWrapper<String>>> is a pretty cumbersome way of saying you want a sparse matrix of string objects wrapped by some special adapter.
Generics facilitate type composure without the need to explicitly create new types. This is a powerful technique, but can lead to very complicated code when abused. Typedefs (template typedefs even better) would result in more concise code and offer explicit meaning, removing the need to look at commments or variable names when you are guessing why the author nested four levels of HashMap. It also helps with nested types.
At least we can take heart that most of the Java collections only take one or two generic type parameters. Fully specified, your average C++ STL container can take up to four type parameters covering everything from type traits to memory management :-)
...with the JDK 1.4!
The problem is that the standard library doesn't implement it.
There are some missing bits, because the compiler doesn't let the programmer use a Class object instead of the class name itself. Which would be very cool btw.
public class Generics
Object data; // Wish I could write: typeInfo data;
typeInfo = Object.class;
public Generics(Class dong)
typeInfo = dong;
public String toString()
return "(" + typeInfo.getName() + ") " + data.toString();
public Object get()
public void put(Object foo)
throw new ClassCastException("Cannot add object of " + foo.getClass() + " to a Generics of " + typeInfo);
data = foo;
public static void main(String args) throws Exception
Generics bar = new Generics(URL.class);
System.out.println("Result: " + bar);
I think one other good things about generics is that
it promotes reuse of collecion classes without wrapping.
I mean, there are really many apis out there which have the
notion of map, set or list, but they usually
wrap the collection api to provide type safeness.
Using generics, this wrapping won't be necessary
anymore, I hope.
public class HashMap<K,V>
implements Map<K,V>, Cloneable, Serializable
public HashMap(Map<? extends K,? extends V> m)
can be in final version look like:
public class HashMap<KeyType,ValueType>
implements Map<KeyType,ValueType>, Cloneable, Serializable
public HashMap(Map<? extends KeyType,? extends ValueType> m)
Well, we have been hearing this critique a lot and many people suggest that type inference could be a solution. I agree to some degree, but there is one other thing: For years, I have found myself writing comments like this:
Map elementIndex = new TreeMap(); //Map<QName,List<Element>>
If the comment wasn't there, people who read the code (might be myself some months later) are forced to search the code for places where the Map is used to find out what the key and value types are. In my example, the search wouldn't be finished until I also find a place where the List used as the Map's value is itself accessed.
Now proponents of dynamically typed languages say: Why don't you give your variables more expressive names? The trouble is, if I include type names in variable names, I have to change the variable names if the type changes and the names would become extremely verbose. So that's really a bad pattern in my view. I'd rather name my variables such that their purpose becomes clear but the same purpose could be satisfied by a variety of types. I could as well have a Map<String,List<String>> to map XML element names to Lists of other elements. This could change as a result of optimisations that I don't want to reflect in my variable names.
The problem with my comments is, however, that I have to keep them up to date. Now, I welcome generics as a way to automatically check if they are up to date.
I Agree. TYPELESSNESS is what's hurting Java at the moment. Ambiguous interfaces using Object and XML descriptors in which everything is a String is where current Java complexity lies. generics + attributes seem to provide a piece of the solution. Between deployment descriptors, JSP, etc. we have been *running* back to the days of finding errors in production, doing stuff by hand, covering up bad design with tools, and discovering API misinterpretations after it's too late; Java was created to get us out of that mess.
Generics are good. But type parameters really have to participate completely in reflection to reach their full potential. I wish that a cleaner syntax than the C++ syntax like
HashMap of (String,int) myMap;
were used...for readability and for the fact that Java code gets embedded in XML based tagging languages. But all that aside, there is a fundamental problem with NOT having type parameterization. This might become more obvious when a competitor like C# comes out with its first class generics, and the tools come out to fully exploit it.
If you were to take an arbitrary object in memory that had some public java.util.List members in its interface, then why can't you just say: bind this object to an url prefix as SOAP protocol? One of the problems currently would be that there would not be a way for the reflection to know what types of objects the List is supposed to contain.
If you take a jar file and run a UML modelling tool on it, what happens whenever collections are encountered? Your design looks like everything is centered around List and Map, and objects that aggregate other objects via such collections classes are apparently unrelated. So, you stop using the standard collections in the interfaces when you need to get the most out of your tools. I believe the lack of type parameterization is why trees, directed graphs, etc never got into the standard collections library; because most valuable graph algorithms naturally return somewhat complex types involving collections. Most real world problems can be attacked pretty succinctly when expressed as simple graph theory problems. That's why we are always drawing diagrams of everything.
Generics will be used heavily by people that are creating reusable components. The actual use of such classes makes things much more readable when casting is not needed, even if the javadocs are a bit harder to read. But hey, the *compiler* (and intellisense from your IDE) can help you interpret the javadocs anyhow. Without the ugly generics, you have to *guess* the intent of the API when it's not completely documented. But generics types need to be fully reflectable to really show their power.
... This might become more obvious when a competitor like C# comes out with its first class generics, and the tools come out to fully exploit it.If you were to take an arbitrary object in memory that had some public java.util.List members in its interface, then why can't you just say: bind this object to an url prefix as SOAP protocol? One of the problems currently would be that there would not be a way for the reflection to know what types of objects the List is supposed to contain...
Yes, you would be right if Java generics implementation would not rely on erasure of the type parameter...
As Anders Hejlsberg clearly explain in http://www.artima.com/intv/generics2.html
" ... when you get to runtime, you don't actually have a faithful representation of what you had at compile time. When you apply reflection to a generic List in Java, you can't tell what the List is a List of. It's just a List. Because you've lost the type information, any type of dynamic code-generation scenario, or reflection-based scenario, simply doesn't work. If there's one trend that's pretty clear to me, it's that there's more and more of that. And it just doesn't work, because you've lost the type information. Whereas in our implementation (ie.: C#), all of that information is available. You can use reflection to get the System.Type for object List<T>. You cannot actually create an instance of it yet, because you don't know what T is. But then you can use reflection to get the System.Type for int. You can then ask reflection to please put these two together and create a List<int>, and you get another System.Type for List<int>. So representationally, anything you can do at compile time you can also do at runtime."
Please note that it doesn't matter that Hejlsberg is the lead C# architect: he said a clever thing and we (ie.: the java community) have to learn from other criticism.
I worked in the MIT Programming Methodology Group and we had a proposal to extend the Java VM to have real generic types back in 1996. It's just a shame that Sun has taken nearly a decade to incorporate generics and now Java has so much legacy code that they couldn't upgrade the VM definition and they felt compelled to provide raw types for transitioning. On the other hand, I appreciate that Sun did not want to include generics until they were confident that they had a sound and carefully reviewed specification.
The best part about generics has nothing to do with "typing my progrom 2 type casts short". It has to do with more obvious semantics.
Today, when you're writing a method that takes or returns any collection type you need to take sure to document what goes into these collections. Now, your docs may not be available at the moment someone else is calling your code -- how can you know what your method needs/returns?
That is by far the best part about generics. Now you can just write Collection<MyClass> load() or save(Collection<MyClass> items) and everything is quite clear.
1. Last time I got a ClassCastException was a couple months ago. It came from a JTable TableModel. Generics won't help here because the class of the thing that gets returned depends on the value passed in as the column index. What's next, a language extension that supports a variable length list of types to cover this scenario?
2. If you hate the performance implications of autoboxed containers as compared to C++ templates, why not just run your Java sources through the C++ preprocessor or another form of code generator? If you do it right, you can make container classes that contain whatever you want, even primitives. It's worked for me, and I got some pretty good performance improvements using primitives...
3. Why not extend the language with indications about whether pointers may or may not be null? Why not extend the language with hints about the relationship of array bounds to other variables? These would reduce more common errors like NPEs and AIOOBEs. Just kidding... if you want to do that, run your code through SPLint (anyone know of a Java equivalent?) and add the appropriate (messy) comments to support the analysis. Nice thing: you can choose code analysis tools independent of compilers.
Admittedly I have a negative initial reaction to generics. I agree that the java.util Javadocs speak for themselves.
A lot of generics performance work has gone into the JVM for 1.5. The compiler inserts casts in a certain way that makes it easy for the JVM to prove that no objects of the wrong type can be used in certain ways. This means much of your generic code's casts are simply erased from the bytecodes / compiled native code at runtime.
Typedefs would make generics 'look' nicer. Then again, you do not see what is under the typedefs. Then you could have typedefs of typedefs to further complicate the stuff. IDEs would show the full definitions of course, but is it really worth it?
Leaving the typedefs out will probably make developers think twice before going overboard with the generics. If your types start to get hard to read and understand, they are probably 'too generic'.
I realize that it is impossible now to halt the addition of generics to Java, but I want to go on record as being completely opposed to this change. I have extensive experience with Java, and I have extensive experience with two other languages that support similar concepts, templates in C++ and generics in Ada. I consider myself to be an expert in all three languages as well as software development in general.
For Java, I believe that the addition of generics does not solve a problem, at least not a problem that I have encountered on any of the projects that I have worked on, but that its addition needlessly complicates the syntax and semantics of the language. I understand that it moves some run-time checks into compile-time checks, and in general that is a good thing, but the benefits in this particular case do not make up for the drawbacks.
In my professional career, I have moved from Ada to C++ to Java (ignoring other languages before Ada), and I found the simplicity and elegance of Java to be a welcome relief. Learning -- and teaching -- the Java language is straightforward. Additional work is required to master the extensive library and related technologies (JDBC, servlets, etc.), but that is exactly where the effort belongs. No other language has such comprehensive support in a standardized way.
I am afraid that they have ruined a great language.
I'm a major proponent of keeping a language as simple as possible. I believe if you minimize keywords and the number of ways to do any one thing you've improved the language.
I understand the need for certain syntactical enhancements (e.g., having for, if, and while constructs) for the sake of clarity. However, having programmed in Java since 1.0, and C++ before that, I have to say I have never once said to myself, "Man, this downcasting out of collections sure is buggy! I wish I had some kind of templating capability in Java to help me keep my collections straight."
In my experience (and we all have different experiences), Class Casts are caught in the development cycle. Rarely, if ever, in QA/Production (especially if you're unit testing).
If I have an object which has a collection/map as a property, I only allow adds and puts through my object. I disallow direct access to my internal Collection/Map. If I need to provide the user a copy of my collection/map, I return it unmodifiable.
Anyway, I don't like Generics. I think it's a horrible addition to Java and will only serve to hurt the language, not to mention the source.