The C# Design Process

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.

The article link
http://msdn.microsoft.com/vcsharp/homepageheadlines/hejlsberg/default.aspx

Slashdot discussion

Well, this is topical:

"…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 is like a List where you use the type Object everywhere. Of course, if you now try to make a List, 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."

…bearing in mind the confusion exhibited here:

http://www.java-gaming.org/cgi-bin/JGNetForums/YaBB.cgi?board=announcements;action=display;num=1074775872;start=19#19

I still don’t get why creating classes at compile time would have effected the VM… guess I’m just dense…

OTOH, I do think that article makes a poor argument for unchecked exceptions and the “lack of them in java”… wierd, I thought there were there…

Kev

java.lang.reflect javadoc (1.5):
"
java.lang.reflect.Method.getGenericReturnType()
… Returns a Type object that represents the formal return type of the method represented by this Method object.

If the return type is a parameterized type, the Type object returned must accurately reflect the actual type parameters used in the source code.

If the return type is a type variable or a parameterized type, it is created. Otherwise, it is resolved."

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

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 :slight_smile: 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.

Cas :slight_smile:

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 :(.

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.

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…?

Just my 2 cents worth…

[quote]Well, this is topical:

"…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
[/quote]
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.

Okay so I have two comments on this:

“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 defeat
that 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…

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


try {
blah();
} catch (Exception e) {
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.

Why enforce a debugging regime?

Cas :slight_smile:

[quote]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.
[/quote]
I have been using it for my day job and I have to say that there’s pretty much nothing to learn- there are about three syntactic differences and that’s it.

I still prefer java but I’m not sure if that is because I feel like C# is kissing up to The Man rather than for any sensible reason…


I still prefer java but I'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 :slight_smile:

Kev

Well, it’s spot on, really… when C# has a good idea there’s no need to go poo-pooing it just cause it came from Satan.

Although the path to Hell is paved with good intentions :smiley:

Cas :slight_smile:

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


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

[/quote]
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!) :


// Incoming data has been flagged by NIO.

try
{
   // 1: read data from buffer into a private data-structure
   // 2: Use reflection to get a protocol-specific handler
   while( // 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: data is still in the data-structure, and if the more generic handler fails too, it can send an error message to the client)
}
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.
[/quote]
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.

I agree. That’s not what Exception’s are for, though.

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


try {
blah();
} catch (Exception e) {
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.
[/quote]
You completely missed my point cas. It’s not the exception block that helps early failure detection. Its that FAILING to write one is caught by the compiler.

Thats your early detection. In order to pass compile you have to at least recognize that the exception condition can exist and do something about it

It prevents oversights and encourages defensive programming which IMO is a very very good thing.

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


try { blah(); } catch (Exception e) {}

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.

Cas :slight_smile:

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.

Power => Responsibility, always a trade I suppose.

Kev

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.

Cas :slight_smile:

Cas, I’m really enjoying reading your posts of recent weeks. The imagery is briiliant :slight_smile:

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.

Kev

[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 :slight_smile:
[/quote]
Tiger adds an @override annotation that causes the compiler to issue a warning if the method does not actually override something.

The performance aspect of his argument seems to be invalid given that JITs like HotSpot will recognise methods which are not actually overridden anywhere and thus don’t need virtual dispatch.

I prefer the Java way of using ‘final’ when you don’t want a function to be ‘virtual’ as opposed to it working the other way around.

Too many times I hit a brick wall because some short-sighted genius made a C++ method non-virtual or private.