Problems with C#
06 Apr 2010I've been using C# at my day job for some time now. When I first started there the place was a little bit disorganized and different projects were using different languages. I did some work in VisualBasic.NET, Perl, C++, and even a little Tcl. Luckily as the place grew we put together some standards, and now all our PC-side and server-side development is done in C#.
Yes, I am deeply involved in Parrot, the dynamic language VM. Yes, C# is hardly a dynamic language (even with some of the new "dynamic" features that have been added in newer revisions). It seems little bit weird that I would be so enamoured with C#, but I am. In fact, I would venture to say that for Windows systems it is my development language of choice. I've heard decent things about Mono on Linux but never used it myself. On Linux, I think my development language of choice may still be C (or NQP!).
However, despite my general happiness with the language there are some problems I have with it. Here are my nits with C#:
Constructors
I feel like constructors aren't given a fair shake, and I have a few issues with their use. For instance, their use with generics is positively anemic:
public void FooThe constaint "Where T : new()" only mandates that the type T has any constructor, but in my Foo method I specifically require it to have a constructor that takes a Baz. Generics are supposed to provide typesafety for cases like this, but it's extremely easy to compile a program with this kind of construct and not have any compile-time indication that the types are incompatible.() where T : new() {
T bar = new T(new Baz());
}
And while we're at it, interfaces should be able to specify a list of required constructors. I'm constantly baffled by this omission, I run into problems from it on a regular basis, and I can't imagine why it wouldn't be possible.
Static Methods in Interfaces
Speaking of interfaces, for the life of me I can't understand why interfaces cannot be used to specify static class methods and properties. I've seen dozens of half-hearted "explanations" for why we don't have this ability, and none of them compel me at all.
Let me give an example from code I was working on this very day. I'm putting together an MDI application which can host a heterogenous collection of child forms. Different form types have different properties: Some are multiplicious. Some are "singletons", where only one child window of that type can open at a time. Some windows should start maximized, and some minimized. Some should open at program startup. Some of this information I need to have from the child form before I instantiate it, so it would be really nice to have a static method on the type that I can call to get this info. Basically, I want to do this:
private method ShowMDIChildThe "..." above really is a variable list of arguments, since different types of child forms may want different argument lists to be created. Sure, I could have a large common list of arguments and force all my forms to implement the same constructor with some of the arguments treated as unused shims, but thats a huge hassle (and I can't specify that constructor in a common interface).() where TForm : Form {
if (IsSingleton() && this.SingletonCache.ContainsKey(typeof(TForm)))
return;
TForm form = new TForm(...);
form.Show()
}
One thing I can do, which is particularly ugly in my mind, is this:
public interface ISingletonMDIChild {}And I think we can all agree that this is a hideous mess. Plus, it would require me to write up all sorts of stub interfaces and treat them like boolean class flags. I could use attributes, but the code to reflect over the class and iterate over attributes is even uglier (and much slower). We also can't always inherit from an abstract parent class because of C#'s restriction to single inheritance. What I want, in a nutshell, is a way to gather a standard set of metadata about classes of a related type in a clean way. I can't think of a better way to do this than static interface methods. I haven't heard any compelling arguments about why we can't do this, but I have heard a lot of half-hearted justifications for it.
...
private method ShowMDIChild() {
if (typeof(TForm).GetInterface(typeof(ISingletonMDIChild).FullName) == null) {
this.ShowMDIChildSingleton();
...
}
Multiple Inheritance.
Yes, it's messy. Sure the implementation would be a little bit messy and the coder would probably have to specify the resolution order manually. I don't care. I find so many cases in my day-to-day coding when judicious use of multiple inheritance would be a perfect solution to a problem, and the alternatives are hackish, ugly, and very difficult to maintain.
Type Switches
Consider the case of a tree control which contains a number of objects of different types. Each TreeNode in the tree contains a reference to that object in the TreeNode.Tag property. When I right-click on different types of nodes I want to see different context menus pop up, depending on the type of the object at that node. That context menu should call methods on the parent form when clicked.
One thing I could do is this:
ContextMenu menu = currNode.Tag.GetContextMenu();But this solution requires the object to build the menu programmatically. To call methods on the parent form I need to do something ugly like pass a variable list of delegates to the object as callbacks, or pass a reference to the Form and make all my methods public, or something like that. Now consider the case where some of the nodes in the list don't have context menus, and some of them call a default version, and we quickly end up with very messy code. What I would really like to do is something like this:
switch (currNode.Tag is) {I guess I could do:
case ClassFoo:
...
break;
case ClassBar:
...
break;
}
switch (currNode.Tag.GetType().FullName) {But that's horrible and unmaintainable. Plus, it doesn't respect inheritance. I could do this:
case "MyNamespace.ClassFoo":
...
if (currNode.Tag is ClassFoo) {But that's horrible too. On the bright side this one does respect inheritance, but then again it is harder to maintain.
...
} else if (currNode.Tag is ClassBar) {
...
}
...
An ability to do a switch statement, which lends itself naturally to multiple alternatives, with object type would be a huge benefit.
Switch Case Fallthrough
And on the subject of the venerable switch statement, it kills me a little bit inside every time I try to implicitly fall through from one case to another and I get a compiler error about it. One forum post I saw actually suggested this gem to workaround the restriction:
switch (whatever) {Gag me with a stick, and deliver me from evil.
case 1:
...
goto _2;
case 2:
_2:
...
}
This is a pretty small list of wishes and, except for the multiple inheritance thing, don't represent huge changes to the language. If anything I think they will make a few tasks much easier. You can complain about my contrived examples if you want.
This entry was originally posted on Blogger and was automatically converted. There may be some broken links and other errors due to the conversion. Please let me know about any serious problems.