Cowboys and Idioms

For the last few weeks, we’ve been engaged in an exercise to port a library of Java code to C#. Not because we’ve necessarily jumped on the C# bandwagon; there’s a customer need to have this library available in two different languages.

Now, I’ve never claimed to be an expert in C#, but I’ve always imagined it as essentially similar to Java. Like Java, it’s semantically compiled to a byte code language. Like Java, it supports classes, interfaces, enums, generics and annotations (“attributes” in C#-speak). So, hey, it must just be a simple matter of translating some of the idioms from one syntax to another. Right? Maybe?

Excitingly, there are some tools that can help here. After trial and error, we settled on an Eclipse plug-in called Sharpen (Alexei did all the time-consuming trial-ing and error-ing, here, acting as our primary code cowboy). It’s fast, it’s well-structured so that we can improve and extend it, and it’s making the more laborious aspects of code translation a lot easier. It’s also more than a bit tricky to find the tool to download. So, with tool in hand, it’s just a matter of pouring Java code in, and getting C# out. Right?

But, hey, Richard Feynman once said that the difference between theory and practice is that, in theory, there is no difference between theory and practice and, in practice, there is.

Mostly, the translation exercise has been straight-forward. There are some key constructs that just don’t seem to want to play nice.

Enums

Yes, it’s true that both Java and C# have enums. But there the similarity ends. C# enums are very much like C or C++. A C# enum is basically syntactic sugar for an integer. Importantly, C# enums cannot implement interfaces, cannot have behaviour, and cannot hold member variables. C# enums also can’t be null. Awkward!

“protected”-level security

In C#, methods and instance variables that have protected-level security are essentially only accessible by subclasses whereas in Java, protected stuff is also visible by other classes in the same package.

Generics

C# generics are very similar to Java in syntax, but there are some important differences. The most significant difference relates to Erasure. I confess that I have a love/hate relationship with erasure. In Java, for example, one can do this:

List<String> list = (List<String>) callConstructor(ArrayList.class);

You don’t need to parameterize ArrayList.class, because the parameters are almost entirely a compile-time artifact. In C#, one can’t get away with that. In C#, the parameter information is an essential part of the “type”, and you need to do this:

IList<String> list = (IList<String>) CallConstructor(typeof(List<String>));

Which, okay. Except when you’re writing a framework that uses reflection, this can be a bit tricky. It’s also somewhat annoying that there doesn’t seem to be an equivalent idiom like this:

List<?> list = getList();
for (Object o : list) {
  // do something to 'o'
}

In Java, this is the idiom for manipulating a list (or other generic type whose contents are unknown) — I’m really missing its absence in C#. It appears that in release 4.0 of .Net, you can do this:

IList<object> list = new List<String>();

But that version is too new to use.

Using/Import

The semantics of “using” a namespace in C# is very different than the semantics of “import”-ing a package in Java. In Java, the import essentially boils down to “can I get away without fully-qualifying a class name?” In C#, your class must declare its dependence on another namespace regardless of whether or not a class is later fully-qualified.

Properties

C# has a more formal property semantic than Java. In Java, properties are almost code conventions. We write:

private String name;

public String getName() {
  return this.name;
}
public void setName(String name) {
  this.name = name;
}

In this kind of setup, we consider the Java class to have a read/write property called “name”.

In C#, this is the equivalent construct:

private String name;

public String Name {
  get { return this.name; }
  set { this.name = value; }
}

Note the use of the magic variable, value. You’d think that this was semantically identical, except that C# introduces naming restrictions on Properties. One can’t, for example, have a “Name” class that has a “Name” property. That kind of thing makes C# sad.

Switch statements

This kind of construct makes C# weep:

CreditCard creditCard = new CreditCard();
switch (customerType) {
case INFREQUENT:
  creditCard.setLimit(5000);
  break;

case SUPER_LOYAL:
  creditCard.setCashback(true);

case LOYAL:
  creditCard.setLimit(20000);
  break;
}

Notice that the second case statement “falls through” to the next case statement. Super loyal customers get a high limit, and cash back. C# thinks (probably correctly) that this is a recipe for programmer error.

Frameworks

Some Java frameworks are so universally useful, that they’re pretty pervasive in any code I write. Commons-Lang, Commons-IO, etc. There are no C# equivalents. There is an NUnit that’s almost identical to JUnit 4. There’s also an NMock, which is sadly more similar to JMock 1.0 (nobody plays with JMock 1.0 anymore, do they?) And Log4N and NHibernate.

Collections

C# really let me down with Collections. There’s a Set type, but no corresponding ISet interface until .Net 4.0. No equivalent to a LinkedHashSet. Similarly, the map choices are a bit threadbare. It’s also easy to get confused by the fact that List and List<X>are two very different classes that have no relationship with one another (one is generic, and the other isn’t! They’re in two different namespaces but you don’t need to fully-qualify either one because they’re obviously different, right?)

Autoboxing

In Java, we’ve had a long, strange, history with primitive types (like int) and the corresponding Object type (Integer). There’s a long, sad, history of having to often convert one to the other, fairly laboriously. In Java 5 and above, the JVM tries to help you out by introducing autoboxing, so you can, for example, do this:

List<Integer> list = createList();
list.add(53);
int sum = list.get(0) + 18;

In C#, the idea of a “nullable” integer (an integer that might have no value) is a fairly recent addition to the language.

int32? index = 53;
if (index.HasValue) {
   int32 sum = index.Value + 18;
}

The C# compiler does not autobox, and gets Downright Testy if you start mixing nullable integers with non-nullable integers.

Conclusion

All-in-all, the languages are more alike than they’re different. We were even surprised to discover a C# development environment for the Ubuntu platform (called MonoDevelop). For us, the issues around generics are easily the hardest items to work around. Not impossible, but harder than I think it should be.

It's only fair to share...
Share on FacebookGoogle+Tweet about this on TwitterShare on LinkedIn

Leave a Reply