View Single Post
Old April 17, 2015, 10:38   #13
Dean Anderson
Join Date: Nov 2009
Posts: 128
Dean Anderson is on a distinguished road
I've been making slow but steady progress, and while I've not found anything near a showstopper, here are my top seven (it was going to be a top five but I thought of a couple more) irritations when porting Cthangband from C to C#...
  1. C# is very finicky about casting. Much more so than C, where you can interchange pretty freely between numbers of different types (byte, int16, int32, signed and unsigned). Where C will generally simply let you copy a value from one type to another and not care if it doesn't fit - you'll just get roll-overs and possibly unexpected results - C# insists on explicit casting. All the time. Not a problem when you're writing new C# code, but a pain when porting old C code.
  2. C doesn't do strings at all well. You have to fiddle around with arrays of characters, pointers, and null terminators. None of that is necessary in C# but again it's very irritating to convert because in C# you don't (explicitly) use pointers (you do actually use them all the time when using reference types, but they're implicit rather than explicit).
  3. C lets you do if statements on numbers, for example if i is an int, you can write "if(i)" and the compiler will understand that you mean "if(i != 0)". C# will throw a compiler error because if statements need to look at a bool rather than an int. So you have to manually add the explicit comparison to zero on each one.
  4. Speaking of bools, C# is very strict that a bool is not a number and a number is not a bool and never the twain shall meet. C doesn't really care, and the C in Angband uses its own preprocessor definitions of TRUE and FALSE which have nothing to do with C#'s true and false.
  5. Did I mention preprocessor definitions? In C# these are all boolean. Either a term is #defined or it isn't. You can't #define a term as a value and then use the term as a macro for that value elsewhere in your code. Well, you can for value types, but the syntax is different. They're declared as variables but with the "const" decorator. You can't do things like "#define SUM(A,B) (A) + (B)" though.
  6. In C#, everything is in an encapsulated unit of code. The majority of the time these are classes but you also have enumerations, interfaces and structs (although the latter are mostly there for API compatibility with C and there's no reason to ever use them in native C# code). There's no such thing as a global scope for variables or functions, they have to be declared inside a class or struct. The closest you can get to a global variable is to give a class a static property or even make the whole class static. In C, of course, every function and variable is global. So that variable in the C code that is declared as being external and then used 269 times in the file as if it were local? Every single one of those 269 times need to be prefixed with the name of the class in which you've declared it in C#.
  7. In C you declare that a variable is an array by decorating the variable's name. In C# you do it by decorating its type. For example in C you have "int x[] = {0, 1, 2, 3, 4}". The equivalent code in C# is "int[] x = new int[] {0, 1, 2, 3, 4}". Similarly where C has "int x[5]", C# has "int[] x = new int[5]". These are functionally identical for the most part, but it's a pain having to change each declaration.

And of course, the thing that's really making me twitch is the fact that I know I'm going to be rewriting most of this code in the next stage of the process where I refactor everything. All the initialisation code I've ported? It's going to be in constructors, not static initialisation functions. All the global stuff? It's going to be in a nice object model, not just scattered around a whole bunch of static classes. All the loading and saving code that reads and writes files byte by byte and has to handle every global variable independently? It's going to just serialize and deserialize the object tree in a half dozen lines of code.

But I have to port it as-is first and get everything working before I start doing the refactoring. Trying to port and refactor the code in a single pass will just end up in a mess.
Dean Anderson is offline   Reply With Quote