July 28, 2007

C# Parital Methods

Update: Orcas Beta 2 is out, and I found a problem in my syntax. Now fixed.

I was just looking through the Orcas Beta 1, and I saw something I have been waiting to talk about...Partial Methods!

This allows you to create a method sub in a partial class so you can provide the implementation in another partial class.

A case where I would use this: in code generation. You generate a data object as a partial class. Now say you want to customize the constructor a bit more. Current you have to use inheritance to do that -- but then you have to remember to use the inherited class and not the generated calss. But with partial methods you can use the main class and provide that logic. Also, if the partial method is not implemented in the other partial class, it is taken out by the compiler. Nice.

A second use: logging. You can stub out methods where you would like logging to occur, but you don't want the partial class to have to deal with the implementation of logging, making it easier to switch out later.

I hope you see why I am excited about this enhancement.

A couple of caveats though,
  1. the method must return void (or a sub for you VB folks).
  2. out parameters are not allowed -- but parameters are allowed in general.
  3. You are not allowed access to internal/private members
  4. They can only be defined and implemented in a partial class.

Below is a stub implementation:

// my generated class in file1.cs
public partial class Class1
{
// a partial method
partial void CalledByInit();

public void Init()
{
CalledByInit();
}

}

// my implementation class in file2.cs
public partial class Class1
{
public void CalledByInit()
{
// do my stuff here
}
}

Now why is this better than:
1. just declaring a delegate in the middle of your class?
2. passing in the code as a predicate parameter?

The answer:
1. A delegate can be assigned by anyone, and potentially have multiple implementations. That isn't always good. The partial method can only have one implementation and only by other partial class.
2. aesthetically that makes a really ugly call, plus it requires that the caller have intimate knowledge of the workings of the method that it shouldn't have to have. Now you can localize that knowledge in one place.

Again, thing about the main use case for the partial method: it should be used in conjunction with code generators. If any of you have used SubSonic, Typed Datasets, NHibernate, or other technologies, right now you are using a mixture of inheritance and partial classes. With this you might be able to drop the inherited class all together. And frankly, I'm for anything that reduces the number of classes lying around a project.

If you are interested in other new features in C# 3.0 I found a nice Power Point from Raj that you can check out.

Partial Methods are mentioned on LukeH's blog.
And they are talked about on the VB Team blog.

July 26, 2007

Some days your better off going home

Yesterday I spent 4 hours trying to solve an "Ambiguous match found" error in one of my ASP.NET applications that I had just converted from a Web Site to a Web Application

For any who don't know the difference, ASP.NET Web Site lets IIS compile the code as needed, but not until then. Makes debugging a nightmare and you have to deploy all of your C# code to the server. Web Applications compile to a dll and you only have to deploy the aspx and dll files.

Anyway, I spent 4 hours beating my head against this problem. I found MANY hits on google, none really helped. Including an often quoted article by Eran Sandler.

Finally I went home. I had to drive 200 miles to pick up my kids from grandma anyway yesterday night (that is round trip mileage). Four hours in a car either by yourself or with sleepy kids does give you time to think tho. I devised a plan.

My problem was confined to one custom control, I had already figured that part out. I would recreate the control piece by piece until I found the problem (don't ask why I didn't think of this earlier).

Next day, nice and fresh, I did just that. I had the problem fixed in 15 minutes. On this particular control I had a Validator control and an event with the same name. That was causing the problem (it wasn't a problem in the ASP.NET Web Site mind you -- just in the Web application).

15 minutes. That was it. About the same amount of time it took me to write this up!

Just goes to prove, when you are really beating your head against the wall over and over again, sometimes it is just better to go home.

July 24, 2007

3 months, 3 LINQ presentations

That is right, in the past 3 months I have given the same basic presentation three times. I don't know if that counts as a groove or a rut. But there are some nice things about doing that: don't need new Power Point for one. But more importantly: more questions that make you question things more.

Starting off, I'm no LINQ expert. Yet I have to distill it to the group. Luckily LINQ is an easy sell. There is something there for everyone in LINQ. But when it gets right down to it, what is LINQ about? I put it like this: FOR loops are evil and LINQ is the cure.

FOR loops are not run for cover and grab a Bible evil, more of a general GOTO type evil. It isn't as if GOTO is evil in itself, in some languages the GOTO is a required statement. But like all inherently benign language constructs, in the wrong hands it can go really badly.

For myself, I've seen some of the worst code in my life nestled in for loops. And even worse, most people don't even know it. How would they? You could say that they just don't know any better. But in reality, there often isn't a better way.

What is the FOR loop but a structured GOTO. Really, that is it. And it isn't a very thick abstraction. If you don't believe me, go check out assembly language. Same with WHILE.

Next, what are you doing in the FOR loop (looping through a list -- DUH)? Sorry, I need a better question: what are you trying to accomplish with the loop? Now, look at the loop, and how easy is it to figure that out after the fact?

There is a reason people don't like assembly anymore, it is too hard to understand after the fact AND it is to hard to write in the first place. There are too many moving parts. Even adding two number (registers) is a multi-step operation. Things you do in loops have many of the same qualities.

Here is an example: find the largest value in an array of integers.

First the array:
int[] i = int[]{1, 2, 3, 4, 5, 6, 7 };

Here is what you write in C#:

int iMax = i[0];
foreach(int j in i)
{
if (iMax < j)
iMax = j;
}

Here is what you would write thanks to LINQ (and Extension Methods):

int iMax = i.Max();

How many ways are there for the first code to go wrong? There are 6 lines, 4 of them have code. There is one obvious bug in the code anyway...what if the list has no items? You will get an index out of bounds error right there. But there are many ways to incorrectly write this code. This is also a simplistic example, so imagine how bad this can get when doing real code.

In the second example: I can't find one. Plus, there is very little chance that you, or someone else, will not understand what the code is doing.

Now this is simplistic, which is bad because it hides the true power that is hiding underneath. There is more to link than grab bag of small statistic functions (e.g. Sum, Min, Max, Count). Add in a complex object and the Where method and we begin to see.

Visualize a customer object. It will have properties like FirstName, LastName, Address, City, etc. This in in a CSV file that is coming from Sales and Marketing.

First part: load the CSV into your program. No problem, we have all done that from time to time. Now find me all of the people in Idaho. Crap.

Not in LINQ. If you loaded your data into a list (List list) you would write code like this:

var idahoCustomers = from c in list
where c.State = "ID"
select c;

Want that in Lambda:

var idahoCustomers = list.Where(c => c.State == "ID");

Something you should know about now, there are two ways of doing the same thing, and you should probably know both. First is LINQ. If you see "from blah blah where blah blah select blah blah" -- you are looking at LINQ. If you see a "=>" you are looking at Lambda.

Personally, I love Lambda more than LINQ. Lambda can do everything LINQ can do, plus everything else. Another way of saying that is "LINQ is a subset of Lambda."

Anyway, this post could run on and on about the wonders of LINQ and Lambda -- but there are plenty of other people doing that. Hopefully, you have already read some of that. Where I want to finish off with is a few suggestions for anyone looking to get a grip on all of this.

First, there are a lot of new things to learn these days. WPF, WF, WCF, LINQ, Lambda, etc. Is this different? Yes it is. You need to learn LINQ. Personally I will be asking interview questions based on link in the future.

Second, considering you have limited time, what should you concentrate on? My answer is Lambda and Extension Methods. The more you learn about Extension Methods the more you will be able to do with Lambda. (Warning, if you are going to learn Extension Methods, you should probably learn about Predicates as well).

And some words of warning. Watch your return value types. You will see a lot of IQueryable, IEnumerable, and other strange interfaces as return types. These will often be hidden in 'var's. Be warned, each has its own capabilities, and you should know how to convert between them.

For example. In a List object, you get the ForEach extension method. You don't get that with IEnumerable or IQueryable. But you can get there by calling ToList() on either of those object types.

Finally: measure. Grab a profiler and run with it. Just like FOR saved you from the uglyness of GOTO, LINQ saves you from the complexity of FOR. But it doesn't get you away from the costs. There will still be times when it is better to write the loop yourself. A good profiler will tell you when.



Oh, one final note: I'm using Visual Studio.NET 2008 Beta 1 like everyone else. All code samples are subject to change when Beta 2 releases this week.

July 18, 2007

Where are the DSLs?

DSL is a Domain Specific Language. It took me a couple of years to really wrap my head around what the term means. Now I have a bad understanding -- but where are the languages?

First off, in my understanding of a DSL, it might not be a proper definition. Frankly, I don't care if the language is a full on language, with it's own syntax and control structures, or just a set of very specific libraries that add classes and methods for easily reading what is going on inside of an existing language -- like C# or VB.NET.

Personally, I like the second one. I would take the inspiration from SubSonic and NHiberate. Heck, throw in NUnit if you want. The nice thing about using these as your examples is that you know things are easily extendable.

There are a couple that I am thinking of right now. I've been playing around with MSBuild and NANT lately. Those two tools have convinced me that XML sucks as a language format. How do you define a loop in XML? You can't do it in any terse format I can tell you that. XML is for data, not logic. That is why JavaScript doesn't look like HTML.

So no, I dont buy XML as a language. Personally, I have a hard time seeing through all of the angle bracket -- really, I do. They just seem to create a lot of unnecessary noise to me. Readability stinks, which hurts the overall expressiveness of the language -- not to mention aesthetics -- and maintainability is also terrible. Not a whole lot of syntax highlighters for xml these days. Debuggability: None. (is debuggability a word?) Either it works or it doesn't. If it doesn't...may the force be with you.

Anyway, back to the build scripts example. Basically, even if you have sample build scripts to work off of, it will easily waist one day of a developer's life to get a build script off the ground. Just to get started. Then countless more hours keeping the stupid thing up to date.

Why don't we have a build script DSL? Some already do exist, Ruby Rake is one. I'm considering learning it. I would like a C# based one, but I'll take Ruby if I have to.

Another use that I have thought of often has to do with ETL. Now I find I'm not alone. Ayande has recently been bitten by the bug. Which is good. Because with his given track record he might just be able to do it. Would you rather deal with Integration Services GUI or a language specifically designed for that purpose.

Bear in mind, these examples break down at one crucial point: threading. Both of the examples mentioned, ETL and Build Scripts, can benefit heavily from working in parallel. And that is one area that our current languages don't help us with a whole lot yet. It is easy to tell Integration Services to load a bunch of tables at the same time in the GUI -- that is a lot more work in C#.

Now it can all be mocked with the Unit of Work pattern so everything can be batched together. That would hide the complexity from the user of the language at the very least. But that still leaves a lot of complexity behind the scenes.

Which leads me to one of the new great hopes coming from Microsoft sometime in the future: PLINQ. Aka: Parallel LINQ. LINQ is all about building a better FOR loop. But it is still iterating over a list one item at a time. PLINQ takes things that next crucial step: multi-threading the iteration. And all without changing the syntax of LINQ. Now that is flippen cool. Unfortunately, I have heard no release date for PLINQ, and it probably wont come out with .NET 3.5 at all.

Anyway, those are my thoughts. I could go on, but I need to get back to work.

July 04, 2007

I (hart) Fiddler

I fell in love with Fiddler today. I was trying to duplicate a SOAP call from one client to my own. Both applications were using the same api to perform the SOAP calls, but one worked, and the other did not (mine was the one that didn't work).

Enter Fiddler. I was able to intercept the call, check what was being sent and returned, and with the help of the file compare in Context I was able to figure out the problem.

Now I've seen Fiddler before, but that was always as a that-could-be-useful-later. Today it was useful. I don't know how I would have tracked down the problem otherwise.