There is an article just out about what went into the design of C#. Interesting stuff to compare and contrast to the current state of Java, with repect to game dev and new language features and adoption in general.

"...And this particular generics proposal [the one that is now in JDK 1.5] had as a key design goal that it could run on an unmodified VM [Virtual Machine]. It is, of course, great that you don't have to modify your VM, but it also brings about a whole bunch of odd limitations. The limitations are not necessarily directly apparent, but you very quickly go, "Hmm, that's strange."

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.

Issue number two, and I think this is probably an even bigger issue, is that because Java's generics implementation relies on erasure of the type parameter, 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, all of that information is available."

Argh! Confusion reigns. I don't care, so long as it means I don't have to type so much.

As for unchecked exceptions: I totally, completely agree with Mr. .Net, he's spot on. Checked exceptions have done nothing whatsoever for the reliability for my code and have usually made it less readable and far more difficult to maintain.

And a few years ago I remember asking for the "override" keyword in the Java language. What a shame that they got it first I think his arguments for nonvirtual functions are fascinating and very good, avoiding as they do some of the manifestations of the fragile base class problem.

And so on. I agree mostly with nearly everything he's got to say. The only reason I haven't run with my tail between my legs to C# is that I've invested too much of my time and brain in Java to be bothering with learning any new stuff for this decade. Java does the job.

Nope, this ignores the fact that Exception's are (should be) nested / inherited / have a tree-structure in the most-frequent case. Yes, there are problems with unchecked exceptions, but it's not as bad as he implies. Often, a developer who has many catch's in a row is unskilled/not thinking in java/incompetent (and the first two are not in any way derogatory, just factual. I wouldn't expect a high-school student to be a skilled systems architect, likewise I don't expect every java programmer to know how to develop java properly).

NB: I'd fire any coder who propagated "Exception" simply because they were too lazy to catch it (one of the cases he cites). That's just bad programming. I've seen (very rarely) coders who make most/all arguments "Object" (not necessarily in java, but certainly in typed langs) so they don't have to worry about types; that in itself is not a valid argument for a typeless language.

NB: Equally, the claim that usually you want to propagate exceptions to be handled by your outer environment implies only that the speaker has limited experience of application design - this is entirely true of certain types of apps, but certainly not of all.

IMHO the real problem with java's checked exceptions only occurs when you are having to catch exceptions that come from different, incompatible, API's (he highlights this), where the Exceptions from each API haven't been incorporated into a common type hierarchy (or, less often, where they have, but you want a different hierarchy).

AFAICS, this is really nothing wrong with checked exceptions in particular, it's a "bug" with java's brand of OO programming. There are other instances of this kind of problem in java, and *all* would be neatly solved in one fell swoop if we could use a dynamic type hierarchy (so you could change the types of things at will). It's a frequent problem also in game-programming where you have very complicated game-logic that needs to be changed frequently - you can't use the OO inheritance system because it's too rigid, and far far too hard to modify at a later date.

You can work around this for exception handling (I have in the past) and make life simple - you have to be a bit cunning though, to avoid being screwed by being unable to alter the typing hierarchy, and it produces a piece of ugly insane code (encapsulated in a private class so no-one need ever see it). You often have to do this kind of yucky thing in java when writing 3rd party libs, so it's nothing new .

Quote

Checked exceptions have done nothing whatsoever for the reliability for my code and have usually made it less readable and far more difficult to maintain.

Having seen the huge differences they can make when deployed appropriately, I can only say that that reflects upon your own coding style rather than anything else. I would hazard your coding style is not suited to java (or vice versa); this may in turn be enforced by your app design, rather than you having the luxury of choosing your style.

Quote

And a few years ago I remember asking for the "override" keyword in the Java language. What a shame that they got it first I think his arguments for nonvirtual functions are fascinating and very good, avoiding as they do some of the manifestations of the fragile base class problem.

I'm going to disagree on whether methods should be virtual by default or not (depends how much OO dev you do, and how you use OO - for instance, 90% or perhaps more of all methods I ever write I'd have to explicitly mark virtual). Wherever the virtual-by-default would be a problem, I generally know at design time, and can use final's; I suspect I'm largely lucky in that the niche I'm in has classes of which this is generally true, rather than this being generally the case. But there's certainly cases where virual-by-default is the best option of the two...

There are also often cases where you can't make something final, but you need to *partially* restrict overriding, and the best you can do in java is a big in-yer-face javadoc comment (e.g. "don't override this unless you also ..."). I would appreciate a better system than either virtual or non-virtual by default, actually...?

"...And this particular generics proposal [the one that is now in JDK 1.5] had as a key design goal that it could run on an unmodified VM [Virtual Machine]. It is, of course, great that you don't have to modify your VM, but it also brings about a whole bunch of odd limitations. The limitations are not necessarily directly apparent, but you very quickly go, "Hmm, that's strange."

For example, with Java generics, you don't actually get any of the execution efficiency that I talked about

This reminds me very much of the C-front days so I, maybe wrongly, don't worry about it much.

In case anyoen wasn't around then, the first C++ compiler came from AT&T, was called C-front, and actually compiled down to (very ugly) ANSI C code.

Eventually true compilers came along which did away with that. I suspect if genercis end up getting a lot of use the VM manufacturers will quickly start warring with each other over the most efficient implementations thereof.

Got a question about Java and game programming? Just new to the Java Game Development Community? Try my FAQ. Its likely you'll learn something!

"Yeah, well, Einstein said that, "Do the simplest thing possible, but no simpler." The concern I have about checked exceptions is the handcuffs they put on programmers. You see programmers picking up new APIs that have all these throws clauses, and then you see how convoluted their code gets, and you realize the checked exceptions aren't helping them any."

(1) He's entirely missed the fact that Java has BOTH checked and unchecked exceptions (children of RuntimeException.) For a supposed compiler-god as they make him out to be thats kinda sloppy.

(2) I have to disagree with him as both a creator and consumer of APIs. I think requiring the programmer to deal with most exceptions is a critical bug-avoiding feature. Used right, checked exceptions give you the abiltiy to enforce a contract where the user of the API has to either handle exceptional cases (basic good defenisve programming) or go out of their way to defeatthat handling.

Its another example of Java's key dsign goal, to 'fail-early', at compilation if possible. C# does not strike me as having the same goal and IMO, as a result the resulting programs are likely to be as failure-prone in the field as C is today.

Ofcourse, based on Windows performance, we can assume that micrsoft doesnt really care much about field failures in general....

Got a question about Java and game programming? Just new to the Java Game Development Community? Try my FAQ. Its likely you'll learn something!

He is quite right though that almost all exception handling in Java that I see today is either

1 2 3 4 5

try {blah();} catch (Exceptione) {e.printStackTrace(System.err);}

or just gets declared to throw Exception. The more you look at it the more you realise that it isn't helping early failure at all. Half the time the exception is effectively ignored because you really can't be bothered with dealing with them deep in some call stack, or you just propagate it up until, typically, AWT catches it, or the Thread catches it and terminates.

As he pointed out, the really crucial and clever bit about exception handling is the "finally" keyword. It doesn't matter whether you System.out the exception or put up a JDialog - so long as you execute your finally {} block to deal with leaving the method cleanly you've effectively handled your exception.

I'd go so far as to say that e.printStackTrace() isn't exception handling at all, it's debugging.

IstillpreferjavabutI'm not sure if that is because I feel like C# is kissing up to The Man rather than for any sensible reason...

Yay! Someone finally admits it. There are "discussions" going on all over the place at the moment that while attempting to make logical arguments either way are actually based more on this type of thing (and other emotional reactions) than anything..

Don't get me wrong.. pure entertainment, just thought I'd highlight it to add to the potential flame victims

He is quite right though that almost all exception handling in Java that I see today is either

1 2 3 4 5

try {blah();} catch (Exceptione) {e.printStackTrace(System.err);}

There's no two ways about this: doing that often is BAD PROGRAMMING. It means you're not attempting to recover from problems. There are apps where it's not worth trying to recover, so this particular bad programming is not just acceptable - it's actually the right thing to do. In an absolute sense, it's still bad programming though.

Here's an example that is typical of what I see, in real code I work with. I've removed most source, leacing in the comments (you wouldn't understand what the heck was going on otherwise, not without knowing the API etc!) :

try{// 1: read data from buffer into a private data-structure// 2: Use reflection to get a protocol-specific handlerwhile( // 3: attempt to interpret the read data as a valid protocol-specific request ) {// 4: ask the handler to remove the data for this request from private data structure// 5: ask the handler to convert the data into an object// 6: ...do some processing on that object... }}catch( // reflection exceptions ){// 2 has failed;// 7: delegate to a more generic protocol-handler(NB: dataisstillinthedata-structure, andifthemoregenerichandlerfailstoo, itcansendanerrormessagetotheclient)}catch( // NIO exceptions ){// 1 has failed;// 8: disaster: check if we are in a special state (e.g. system is shutting down, in which case this is expected; do nothing)// 9: log stacktrace to system log, trigger an alert in the admin interface// 10: AND put this particular subsystem into the "OFFLINE" state, so that it will not be asked to handle future requests.}catch( // parsing exceptions ){// 11: invoke methods on the protocol-handler to get standard error messages for the particular parse exception// 12: send these messages to the client (NB: this delegates to another IO-sensitive piece of code, which has it's own error-handling)}

[/quote]

Quote

As he pointed out, the really crucial and clever bit about exception handling is the "finally" keyword. It doesn't matter whether you System.out the exception or put up a JDialog - so long as you execute your finally {} block to deal with leaving the method cleanly you've effectively handled your exception.

Yes, finally is very important and powerful (it actually provides semantic behaviour you cannot achieve without it, as well as being a convenient time saver in some situations).

However, there are many cases where finally isn't a complete solution in and of itself - see above, where proper error recovery can only be achieved by knowing what went wrong. Note that, although it's not the best example of this, there is some automatic recovery you CAN do for certain types of errors.

Quote

I'd go so far as to say that e.printStackTrace() isn't exception handling at all, it's debugging.

Well, the trouble is, it doesn't do anything of the sort, because code is littered with

1

try { blah(); } catch (Exceptione) {}

right the way down into the JDK. It makes the compiler shut up and hides the exception, which is probably not what the language designers intended. If on the other hand there was no requirement to actually catch exceptions, then they'd be propagated right up the call stack and eventually trip up the thread, and get printed out and noticed.

So, then you're saying that every exception should be derived from RuntimeException then?

I think there are some times when its really good to use checked exceptions tho. Component interfaces generally seem to be a good bet. The flexibility is nice to have, but I guess you're coming from a "if everyone had to do it this way then it'd never be misused" perspective.

I'm all for simplicity. That's why, for example, I like delegates. I was greatly saddened that they were deliberately shunned by Sun because M$ "invented" them. I suspect legal and political machinations may have ultimately decided that one for us though, as it was a key factor in the "polluting Java" trick M$ tried to pull off.

In the end, forcing programmers to catch exceptions but then not enforcing any action when they are caught is basically as safe as handing kids matches and a can of petrol.

No wonder the "design by contract" lobby are so vociferous, as DBC promises to actually manage the interfaces between components properly, rather than allowing all these little kludges to slip through the cracks.

Trying to be pragmatic about this, I think there is still a trade off. Checked exceptions are a useful tool, should you deny it from all programmers because some programmers arn't bright enough to use them properly.

I guess its more a question of do we ban petrol altogether because children might hurt themselfs. Maybe its a good idea, but its a long ole' walk to work.

Does the above imply that information about Type (Type ~= class name?) is indeed saved or not?

That's just the statically compiled type parameter information. You can't retrieve the actual type a class was instantiated against. Type erasure means that the types aren't carried around at runtime - the information just isn't there, in any form or fashion.

Argh! Confusion reigns. I don't care, so long as it means I don't have to type so much.

Confusion only reigns because people can't be bothered to RTFM.

As far as less typing goes, generics will save some casts here or there, but it sure won't help out those people (say everybody who posts to this board) who need primitive-based, parameterized collections. <sigh>

generics will save some casts here or there, but it sure won't help out those people (say everybody who posts to this board) who need primitive-based, parameterized collections. <sigh>

...but it will *greatly* help library and middleware authors. We actually seriously considered the insane step of using a beta JVM (1.5) for a production system, because of the amount of programmer time it would save.

...but it will *greatly* help library and middleware authors. We actually seriously considered the insane step of using a beta JVM (1.5) for a production system, because of the amount of programmer time it would save.

I'm not sure that *greatly* is the expression I'd use, but the JDK1.5 language is a significant improvement over 1.4, even if generics aren't all they should have been.

As far as the 1.5 beta goes, I wrote a tool, Retroweaver, that translates 1.5 class files to 1.4. So we compile with JDK1.5 beta, taking advantage of generics, extended for loops, static imports, yada yada, and we deploy to a production 1.4 VM. So, maybe you should reconsider using 1.5.

@Metadata seems to have been overlooked. To my mind it appears to be as useful as generics, if not more so. The amount of crappy boilerplate code I keep having to write is just insane. How excellent is it that I can automate most of it with metadata?

@Metadata seems to have been overlooked. To my mind it appears to be as useful as generics, if not more so.

For me, it seems both useful and dangerous. One of the strengths of java was inability to create your own dialects of language (which was possible in C with heavy use of macros). I'm afraid that with overuse of metadata, you can become lost with number of magic modifiers which will appear in class definition and change way it works in program in subtle ways.

Not that there is any viable alternative - putting metadata in separate config files (like currently in J2EE) is probably even worse. But at least it was tiring enough for people to use it only when really needed, not just-for-fun.

I wonder what will happen when aspectj will meet metadata (pointcuts on annotations seems most obvious).

For me, it seems both useful and dangerous. One of the strengths of java was inability to create your own dialects of language (which was possible in C with heavy use of macros). I'm afraid that with overuse of metadata, you can become lost with number of magic modifiers which will appear in class definition and change way it works in program in subtle ways.

Me too. For a lot of the boiler plate I encounter in java, there are more elegant or less dangerous ways of generating it than metadata (sometimes as simple as just more intelligent use of OO; or the use of 3rd part libs that go to great pains to make it easy fo ryou to not need to boilerplate *nor* need to use something as powerful as metadata). But IME nothing that comes close to being one unifying "always at least as good or better than metadata"; you'd need a whole bag of tricks instead.

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