(This was originally meant as a comment for Janus’s post about C#, but it turned out to be longer than that…)
Mikkel and I have to learn C# for understanding the code from SCET, a project running before our project. Anyway, we’ve been looking at a tutorial, the one over at http://csharp-station.com/ (just a random one).
And so far my impression of C# is that it is like C++ with garbage collection (so it’s a bit like Java) and with new keywords such as ref
, out
, etc for parameter passing. The ref
is nice and clearer than pointers or C++ references so that’s good.
But the out
keyword? I think it’s ugly. First it’s not necessary, just pass a ref
parameter and have the method update it. A better solution would be to let methods return multiple values in a — ohh — tuple! That cannot be so hard, especially because it could be implemented as syntactic sugar for the out
parameters. Several languages (Python, ML and Haskell comes to mind) have such a construct and it is very useful.
Also, who uses goto
these days? I think that is a bit too low-level. But maybe it reflects that C# is mostly C++ with a standard garbage-collector?
The choice of having methods being non-virtual as default is also unfortunate. For you simply cannot predict if a given method will need to be specialized in the future. It hurts extendability if you have to go change the base class when you want to specialize a function in an derived class — the source for the base class might not even be available in which case you are stuck. The efficiency concern of virtual methods is not valid, IMHO. First, the compiler should be able to look at the class tree and note that method foo()
isn’t redefined and thus make code that jumps to foo()
just as efficiently as if it had been declared non-virtual. Second, the extra pointer indirection incurred for virtual functions shouldn’t be a problem with our modern fast CPUs and with normal programs that spend 99.9% of their time waiting for user input anyway.
In the book Object-Oriented Software Construction it is described how it is always right to call the redefined method B::foo()
and often wrong to call A::foo()
if class B extends A and if you want to take advantage of polymorphism. The problem is with invariants: since foo()
is redefined in B it presumeably adds some functionality to A::foo()
, it might update some internal state in the object to maintain a class invariant in B. Class A does not have the same class invariant as B and so calling A::foo()
destoys it whereas calling B::foo()
would have been the right thing to do. The method B::foo()
is always safe to call since it must fulfill both the invariants of class A but also of B. Even though class invariants is something you mostly see in Eiffel code, the principle applies to all languages.
I also don’t get why delegates was invented — aren’t we just talking about a function pointer? It seems that I can declare a delegator for comparing numbers like this
public delegate int Comparer(object obj1, object obj2);
after which I can say
Comparer cmp = new Comparer(CompareFirstNames);
when the CompareFirstNames()
method has a signature matching with the delegate just declared. One can then of course pass cmp
to a sort()
method as usual. But why could I not just pass CompareFirstNames
to sort()
directly? Why do I need to make a new delegate type (if it is a type, I’m not really sure…)? The notion of agents in Eiffel seem much more elegant and powerful. I would be happily surpriced if someone tells me that you can pass a semi-instantiated function as a delegator in C#. Agents in Eiffel work much like lambda functions in functional languages, giving you the possibility to easily adapt functions for use as callbacks. (Agents are described and compared with .NET delegates here, see also the OOSC course homepage.)
That was a lot of initial comments about what I’ve seen from C#. Don’t take this as meaning that it’s all bad — the idea of properties is a good one, for example. A garbage collector is also something which I’ve come to expect from a modern language, so that too is a welcome change from C/C++.