• Advertisement
Sign in to follow this  

[java] Question about generics

This topic is 4423 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

So I've got this class that can determine a price for several different goods. I often want to sort by this price; since sorting is time-consuming and frequent, I am concerned about performance. (I may be optimising prematurely. Please consider this also as a theoretical question, because I'm new to generics and want to learn how they work.) Here is my class :
abstract class Bidder implements Comparable<Bidder> {
  private static int sortByIndex;

  public double getMaxPrice (int thisResource);
  public double getMaxAmount (int thisResource);


  public int compareTo (Bidder dat) {
    // Not consistent with equals.

    if (getMaxPrice(sortByIndex) > dat.getMaxPrice(sortByIndex)) return 1;
    else if (getMaxPrice(sortByIndex) < dat.getMaxPrice(sortByIndex)) return -1;
    else return 0;
  }

  private static void sortBidders (Bidder[] theBidders, int index) {
    // Sorts the Bidders in order of their price for index.
    sortByIndex = index;
    Arrays.sort(theBidders);
  }
}

The question is, is this the same as, faster than, or slower than the old 1.4.2 method where I would write an explicit cast into the compareTo (Object) method? I don't quite understand how the underlying bytecode works; I know it's not the same as a C++ template, but apart from that I am clueless. Could someone enlighten me?

Share this post


Link to post
Share on other sites
Advertisement
Sun has a nice PDF lying around which explains a lot about generics:
http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf

In general, generics do not add any runtime overhead. They do nothing which you could not do with a few casts yourself (and indeed the actual byte code only does those casts automatically). They can also be useful during compile time because it's much harder (but not impossible, especially when dealing with legacy code) to add the "wrong" instance to a collection.

Share this post


Link to post
Share on other sites
Quote:
Original post by BitMaster
In general, generics do not add any runtime overhead.

And, alas, Java generics don't *remove* any runtime overhead either.

Share this post


Link to post
Share on other sites
OK, so generics basically save me the trouble of doing my own casts, and turn a bug that would otherwise be a runtime ClassCastException into a compile-time bug. Fair enough, those are worthwhile things even if not as powerful as C templates. I wonder, though : Is it possible that Sun will, in a future version, make generics more template-like? Are there fundamental issues with how bytecode works that prevents this, or was it only a decision to get something out there and then improve it later?

Share this post


Link to post
Share on other sites
The really nice thing about generics is, that they can interwork seamlessly with legacy code. Basically, they just introduce a few implicit casts into the byte code. This is good (does not break any code and allowed them to add generics to all n+1 things in the Java standard library which could use them in some way) and bad (not as powerful as C++ templates or at least like C# generics).

I'm a bit tied on the bad points though. C++ templates are one of those things which can be used for incredible good, but they can also cause major headaches, make code generation much more complex and vastly increase compile time. Also, some things, like for example compile time polymorphism, are not really necessairy in Java because a modern VM should be able to optimize it anyway.

My C# knowledge is rather limited, but I believe their generics compile into a different class for each instatiation, which would elimate a few casts but might limit your ability to work with legacy code.

All in all, I can often see the Java guys' dilemma. On the one hand, the very idea was to make a much cleaner language than C++ but on the other hand you end up missing some things. Like operator overloading. Sometimes you can really miss it in Java. Then you work with some C++ code where someone defined not exactly intuitive operators which meaning you had to rip out of the code first and several different overloads and none is well documented or easy to find in the code. Then you understand the decision not to include operators. Although you can make the same overloading mess with normal function names, you will usually get different method names for operator +(MyCollection, MyCollection) depending on whether we are talking about concating collections or componentwise addition.

Share this post


Link to post
Share on other sites
Thinking about this, it occurred to me that it wouldn't be incredibly difficult to make a preprocessor that took your code and made new classes (in high-level Java) for your templates. Then you could feed that to the Java compiler to get the bytecode. Does anyone know if something of the sort has been done? I Googled for 'Java preprocessor' and got some hits, but they seem mainly to be about C-style macros; I got nothing on templates.

Share this post


Link to post
Share on other sites
It's a bad idea. If you need some autogeneration, setup one in your IDE. If you'd like to see why is preprocessor bad idea, look at x264 source code (I really think that some results were unwanded by programmer.).

Share this post


Link to post
Share on other sites
Quote:
Original post by BitMaster
All in all, I can often see the Java guys' dilemma. On the one hand, the very idea was to make a much cleaner language than C++ but on the other hand you end up missing some things. Like operator overloading. Sometimes you can really miss it in Java.


You could start programming in Eiffel. It is more or less like Java, but with some minor, yet smart differences, it has Operator Overload, AND Design by contract, AND Multiple Inheritance, AND compiles to the language of your choice, typically Java or C/C++... (but I like java for NOT having those things, and the compilie to C/C++ is possible SEE Antlr, and some GNU stuff).

Quote:
Original post by King of Men
Thinking about this, it occurred to me that it wouldn't be incredibly difficult to make a preprocessor that took your code and made new classes (in high-level Java) for your templates. Then you could feed that to the Java compiler to get the bytecode. Does anyone know if something of the sort has been done? I Googled for 'Java preprocessor' and got some hits, but they seem mainly to be about C-style macros; I got nothing on templates.


You could do that...see XDoclet, and XSLT, for code generation, and then you would want something to pretty up the code so look at Checkstyle, or JIndent. But in general preprocessing isn't the best choice. And some IDE macro would probably do just as good a job.

Quote:
Original post by Arild Fines
And, alas, Java generics don't *remove* any runtime overhead either.


Could you point me to where there is documentation as to whether or not this is true? From a language design POV generics should remove the runtime check for proper cast...AFAIK.


L-

Share this post


Link to post
Share on other sites
Generics can't remove run-time overhead as they are implemented using a technique called type erasure. The bytecode generated has no knowledge of generics at all. The compiler inserts casts in the code having already trapped most of the potential ClassCastExceptions at compile time.

However you should know that a runtime cast is an incredibly fast operation and nothing you should be concerned about.

Cas :)

Share this post


Link to post
Share on other sites
Quote:
Original post by princec
Generics can't remove run-time overhead as they are implemented using a technique called type erasure. The bytecode generated has no knowledge of generics at all. The compiler inserts casts in the code having already trapped most of the potential ClassCastExceptions at compile time.

However you should know that a runtime cast is an incredibly fast operation and nothing you should be concerned about.

Cas :)


Thanks, I'm not overly concerned about the operation. (Its probably on par with bounds checking an array, but doing a lot of that can make a program slow. Which it probably is checking some constant from the byte-code generation.)

Can you explain "type erasure" or point to some documentation please.

Thanks,
L-

[Edit:] Actually nevermind. Google found it for me, thanks.

Share this post


Link to post
Share on other sites
Quote:
Original post by BitMaster
My C# knowledge is rather limited, but I believe their generics compile into a different class for each instatiation, which would elimate a few casts but might limit your ability to work with legacy code.
no, this would be how C++ works, making copies of the class specific to each data type used. C# utilizes one class that maintains type information on the data. It required a large change to the underlying CLR to make it work. However, MS is operating on a different philosophy for the .NET runtimes than Sun is for the Java runtimes. MS has decided to forgoe backwards compatibility and has enabled .NET runtime environments to coexist seemlessly with each other. So, theoretically .NET should not end up with the same API bloat of deprecated classes and methods as Java.

Share this post


Link to post
Share on other sites
That's why we're sticking with Java :) Need to know stuff is going to work everywhere, for a while longer! The Java runtimes co-exist peacefully with each other too.

Cas :)

Share this post


Link to post
Share on other sites
Quote:
Original post by princec
That's why we're sticking with Java :) Need to know stuff is going to work everywhere, for a while longer! The Java runtimes co-exist peacefully with each other too.

Cas :)

no, each subesquent runtime supercedes the previously installed runtime. While it may leave it installed, your programs will always try to run off of the latest runtime. With .NET, your programs will always try to run off of the runtime they were built with. I feel this is a better policy because I have seen first hand that the JREs are not fully backwards compatible, especially concerning graphical stuff.

Share this post


Link to post
Share on other sites
No, that's not true. The default behaviour is to run with the latest version of the JVM, but you can a) embed the runtime in your software bypassing the problem completely (like I do) or b) specify in the Webstart JNLP file which VMs you want to use and the order of preference that they should be used in, to some degree.

Cas :)

Share this post


Link to post
Share on other sites
Quote:
Original post by capn_midnight
Quote:
Original post by BitMaster
My C# knowledge is rather limited, but I believe their generics compile into a different class for each instatiation, which would elimate a few casts but might limit your ability to work with legacy code.
no, this would be how C++ works, making copies of the class specific to each data type used. C# utilizes one class that maintains type information on the data. It required a large change to the underlying CLR to make it work. However, MS is operating on a different philosophy for the .NET runtimes than Sun is for the Java runtimes. MS has decided to forgoe backwards compatibility and has enabled .NET runtime environments to coexist seemlessly with each other. So, theoretically .NET should not end up with the same API bloat of deprecated classes and methods as Java.


Doesn't C# (or the CLR, of whatever) specialize generics for struct-types (so, no boxing necessary, and better performance), but reuses one single class for class-types (but which contrary to java has still access to type parameter information)?


Found it: On MSDN

Quote:

When a generic type is first constructed with a value type as a parameter, the runtime creates a specialized generic type with the supplied parameter or parameters substituted in the appropriate places in the MSIL. Specialized generic types are created once for each unique value type used as a parameter.

Share this post


Link to post
Share on other sites
Quote:
Original post by princec
No, that's not true. The default behaviour is to run with the latest version of the JVM, but you can a) embed the runtime in your software bypassing the problem completely (like I do) or b) specify in the Webstart JNLP file which VMs you want to use and the order of preference that they should be used in, to some degree.

Cas :)

two problems with your two solutions. Letter A kills binary cross platform compatability. Letter B presupposes that one is using Webstart, which is quite buggy in its own right.

Share this post


Link to post
Share on other sites
Binary cross-platform compatibility is some sort of techno-utopia which is a bit of a joke in the real world of application deployment. If you want to use Java and deploy reliably anywhere, you must embed the VM for Windows and Linux deployments, period.

Yes, Webstart is a bit shit, but at least it's being improved ;)

Cas :)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement