Moderately Clever .NET Trick #1
September 22, 2007 programming No Comments
System.Nullable
System.Nullable
Java has three major types of collections:
These are then broken down into implementation-specific subtypes, each of which has applicable uses depending on the situation:
.NET has a similar yet deficient family of collections:
The implementations are even more sporadic:
In Java, I regularly used 5 different collection implementations depending on the circumstances; in .NET I only have 3 that are normally useful, and the gaps are not easily filled.
Consider this code:
public delegate void AnAction(); private static ListgetActions() { List actions = new List (); for (int i = 0; i < 10; i++) { actions.Add(delegate() { Console.WriteLine("i is:" + i); }); } return actions; } static void Main(String[] args) { List actions= getActions(); foreach (AnAction action in actions) { action(); } }
If you run this code, you do not get a series of lines stating “i is: 0″ through “i is: 9″. You do not get any errors, warnings, or exceptions at either compile or run time either.
What you get is this:
i is: 10 i is: 10 i is: 10 i is: 10 i is: 10 i is: 10 i is: 10 i is: 10 i is: 10 i is: 10
When the delegate is added to the collection of delegates, it’s using the actual variable “i”, not the object that the variable is referencing at the time. (This applies for both reference and value types.) By the time the delegate collection is accessed and the actions are invoked, “i” has the value “10″ (which, by the way, is outside the normal operating range of the loop), even though “i” is no longer in “normal” scope.
This almost makes some sense, even though I think it’s counter-intuitive (and thus bug-encouraging). The .NET inventors had to choose between referencing the variable and referencing the value; there’s use cases for both. However, it starts getting really strange when you make a copy of the variable, as in this replacement code:
private static ListgetActions() { List actions = new List (); for (int i = 0; i < 10; i++) { int x = i; actions.Add(delegate() { Console.WriteLine("i is:" + i + ", x is:" + x); }); } return actions; }
i is:10, x is:0 i is:10, x is:1 i is:10, x is:2 i is:10, x is:3 i is:10, x is:4 i is:10, x is:5 i is:10, x is:6 i is:10, x is:7 i is:10, x is:8 i is:10, x is:9
Upon invocation, the delegate references the variable “i” but the value of “x”. How and why it makes that choice is beyond me.
C# made two big language improvements over Java:
Both are great innovations, but the stupidity comes when you mix the two. The “override” keyword is only allowed when you’re subclassing; if you’re implementing an interface it is specifically disallowed. That means that you cannot, after all, easily flip the superclass to an interface (or vice versa) without changing the subclasses if the subclasses override any methods (in particular abstract methods, which are effectively the same beasts whether you’re subclassing or implementing an interface). So close…
Say you want to compare two objects (typically for sorting). How do you do it?
You may want to consider the following:
That’s 7 types to be aware of, and only one that you should really ever use.
I’m working on a .NET/C# project, which is a new environment/language for me after years of Java development. Thusfar, .NET appears to be a pretty decent language, although most of the good stuff in the language directly mimics Java. .NET did managed to fix a few of the problems with Java, but also failed to fix ones that could have been fixed without the burden of backwards compatibility.
The reason for my post though is that .NET has introduced a few new problems that shouldn’t exist. Microsoft, with all their resources and plans for language domination, really should have known better. I’m calling these “Stupid .NET Tricks” in homage to Letterman.
My first example is one that bugs me on a daily basis:
For example:
public delegate int ValueGetter();
public void displayValue(ValueGetter getAValue) {
if ( weReallyWantToDisplayTheValue() ) {
int x = getAValue();
display(x);
}
}
private int aValue;
public int AValue {
get { return aValue; }
set { aValue = value; }
}
public void displayAValue() {
// This isn't allowed, even though it makes perfect sense
// displayValue(AValue);
// Instead, you have to do this:
displayValue( delegate() { return AValue; } );
}
Note that displayValue calls a method which calls a method on the property (both methods having the exact same signature), rather than just calling the method on the property itself.
Delegates are easily the best feature .NET has that Java doesn’t, but this oversight steals some of the thunder.
Eric Burke claims that check exceptions introduce implementation dependencies into your code:
Because the DAO throws PersistenceException, the next higher layer of your application must deal with it. This is a big problem, because this means your business logic now has persistence framework dependencies. What if you want to write a DAO that uses direct JDBC instead? Or you want to switch to Hibernate? Oops…every layer of your app depends on the old persistence API thanks to checked exceptions.
Here’s his sample code:
public class DefaultCustomerDao implements CustomerDao {
public Customer findById(Integer customerId) throws PersistenceException {
...do something with the persistence framework that throws PersistenceException
}
}
He claims that the calling code now has to know about PersistenceException, and that’s bad. He’s right on the surface of course, but I think he misses a point: the calling code already has to know about details of the persistence mechanism: it has to know about findById(), which in turn is a part of CustomerDao. (These classes are part of his fictional persistence framework that could be switched out for some other framework).
If you’re already dependent on CustomerDao and findByID() for your calling code, then adding a dependency on PersistenceException is not much worse. Thanks to the Law of Leaky Abstractions you’re probably more dependent on your persistence framework for more than APIs anyway; your code will almost certainly be structured around the API’s paradigm, so switching to another one will involve a lot of work regardless of whether it uses checked exceptions or not.
What you can do to minimize all this is to abstract your persistence mechanism behind a new API and paradigm that you control. This API would then call the API that does the actual work. You could swap out implementations of your API as you see fit (although due to the leaks it will still involve some recoding).
Under such a system, whether a framework uses checked exceptions is entirely irrelevant; it’s completely up to you whether you want to use them or not:
I believe that your “real” code should be (at least) one abstraction away from any third-party library or framework, whenever possible. This gives you the least dependence on it should you want/need to change it down the road. Depending on the maturity of the library and the prevalence throughout your project, wrapping it in an abstraction layer is usually well worth the additional work: you gain flexibility (which is crucial in any project) and can “fix the problems” (as you define them) in the API as you go along.
(Perhaps surprisingly, this is my first Java-related post. What’s surprising is that I do Java for a living; I guess that I talk enough about it during the day that I don’t feel much need to blog about it on my own time
IM conversation between my boss (who recently got a new MacBook Pro) and myself:
Ted: gah!
Ted: eclipse is NOT a happy camper on OSX — crashes a LOT on stupid stuff like “refresh”
Craig: hrm
Craigo: good thing you don’t do any programming any more![]()
Ted: ah ha ha
Craigo: “I’m a PC”
“And I’m a Mac”
“Hey PC, get your damn work done, I’ve got to go to a meeting”
Microsoft really did themselves a disservice when naming their new programming platforms C# and .NET; they’re both nigh unto unsearchable. Many search engines drop “special characters” during their word parsing, which means that “C#” becomes “C”. Not only does that match two other languages, but it also matches any sort of line “c” (ie: used in an outline). “.net” of course matches the “.net” top-level domain, and also potentially the “net” used to catch fish. Google seems to figure out C# (it still chokes on .NET) but other site-specific search features don’t. Really annoying
Theme Change #0: Check to see if “Shaded Grey” is free-license enough for me to edit it. (I think about that sort of thing a lot these days). Hrm, looks like it isn’t; at least it’s not clearly demarcated enough for me to chance it.
Theme Change #0.5: Start working on a custom theme.
Theme Change #1: Get rid of the ugly border that’s the HTML/CSS default on hyperlinked images.