04-16-2009, 12:05 AM
|
#10 (permalink)
|
| CEO of Brooklyn
Join Date: Oct 2005 Location: Brooklyn
Posts: 10,092
My Mood: |
More commentary Quote:
C# Sucks S***
July 07, 2004 22:03:11 EDT
"Simple things should be simple. Complex things should be possible". It could be slightly misquoted (I'm going from memory), but I like that quote (From Alan Kay?). I'm currently going through a headache of magnificent proportions, because I have finally reached the point where I can do some basic coding in Smalltalk, and its made me realise just how ****ing poor C# really is.
The Project: The HL7 Parser part of an HL7 Compliant TCP/IP Server.
The Problem: Refactoring a Segment class so subclasses can implement specific behavior (Right now one Segment class with boolean conditionals, its only OO in the sense that is wrapped in a class)
The Solution: Create a static method on the abstract base class. Parses the first 3 characters and gets an instance of the correct subclass.
Sounds easy doesn't it. So I attacked it like so.. Create a static dictionary, use reflection to get all subclasses of Segment, add each to the dictionary, using their specific 3 character segment code as the key, and a Type as the value... This is where it becomes painful. Painful because the smalltalk version is so ****ing simple.
subclassesBySegment isNil
ifTrue: [ subclassesBySegment := IdentityDictionary new.
self subclasses do: [ :aClass | subclassesBySegment at:
aClass segmentCode put: aClass ]].
So now, I have a string of text, I can read in the first 3 characters (aStream upTo: $|) | is the segment separator, and go to my subclassesBySegment dictionary and pull out the class and create it:
segment := (subclassesBySegment at: #MSH) new.
Simplified (It would normally be read from a stream, sent to dictionary, and probably call at:ifAbsent just in case, to create an instance of a GenericSegment or something... ANYWAYS)
Now I tried to do the same thing in C#. It is just a ****ing nightmare.
IDictionary map = new Hashtable();
Type type = typeof(Segment);
Thats as far as I got, because guess what I have to do next? Go through every ****ing type in the system, checking t.IsSubclassOf(type), and if its true, add it to the dictionary...
But thats not all.. See, the Smalltalk version also allows me to just call segmentCode on a subclass, thats a dynamic language for you. Not so in C#. Because Type does not know what the **** the segmentCode method is. So now I have to go into reflection mode:
MethodInfo m = t.GetMethod("segmentCode", BindingFlags.Static);
String key = (String) m.Invoke(t, new object[0]);
map.Add(key, t);
Ok, so now I have done that.. Remember the smalltalk code to pull an instance of an MSH segment out? segment := (subclassesBySegment at: #MSH) new. Great! Lets look at C#: Segment segment = (Segment) Activator.CreateInstance((Type)map"MSH");
Yes, I could have changed it so instead of storing the Type, I stored the ConstructorInfo instead, but thats even worse. I won't even go into that.
Its just ****ed. Trying to create code that reflects on itself and generators tables or whatever at runtime is about 100 times harder than it needs to be. All in the name of compile time safety. I'll take my chances with the dynamic code I think. In my dreams of course, because people at work don't know what the **** Smalltalk is. So the only way I get to use it is as a form of torture on myself... "Oh Sean, you could be finished by now. Instead you've got the ****ing .NET Framework Documentation open and your trying to work out how to do what you need to do... You could be finished by now. HAHAHHAHAHAHAHAH()@!#^(*&#$^@(Y@EOI@#"
Do you know what else I hate? the static keyword. The way Smalltalk class methods are design is brilliant... You know you can actually define a contract on class (static) methods as well? C# just ****s off an error at you specifying interfaces can not contain static methods. Static methods can not be overridden, and so on and so forth.
Comments
| |
| |