If You Want to Understand C#, Then Don’t Waste Time Studying C#: Delegates vs Interfaces in a Nonfunctional World

“The new features being introduced like closure, continuation (yes, yes very limited continuation) in C#2.0 and now type inference, lambda expressions are de-generating the language. Even though there are people go gaga about continuation and lexical closures these are fundamentally functional language features and should be left to that. Introduction of bits and pieces of functional language features are not going to add value to C# and at the same time the surface area of C# is growing beyond what most developer can grasp.” — Abhinaba

“There are plenty of people who realize that learning LISP will make them incrementally better programmers, but that they may have done the calculus, and the the intellectual capacity might be better spent focused on the problem domain.” — Anonymous

So I installed Visual C# 2008 Express Edition to check out the new C# 3.0 features. The installation failed a couple of times and I went to check the Windows Updates to see if I was missing anything. A few random security updates and a whimsical installation of IE7 and several reboots later, I discover a service pack for .Net Framework 2.0 that has a note on it saying that its required if you want to install the .Net Framework 3.5. (Let’s see… .Net Framework 3.0 was not a replacement framework like you’d think it should have been… so thinking that 3.5 would just magically work on its on is silly because 3.0 wasn’t really a 3.0, it was really a 2.5… so maybe 3.5 isn’t really a 3.5; it’s really more of a 2.75… and that’s why I need service packs for 2.0. Maybe. How could I have been so stupid as to think that the installation would just work?!)

Alright… let’s see…. A good while back, I was looking for a C# job and came across a lead that sounded too good to be true. Several phone interviews later, I discover that it wasn’t really a job, but an extremely expensive training program that could “almost certainly” guarantee me a job when I completed it. The flirty sales rep almost had me convinced to sign the papers to take out a loan. I had the print-outs from Sallie Mae and everything. They sounded really smart to me. People that got their training just went out and changed the world. As I was just about to close the deal, I asked my last question. “Will I understand delegates if I take your course?”

I didn’t really get a clear answer on that one, so I hesitated….

Crazy, huh? I’d read an article about them and, yeah, maybe I could imitate the code and create a silly example… but I just couldn’t see the implications of that language feature. Why should it be so useful? I thought I understood Object Oriented Programming and the whole concept of a Delegate just seemed so foreign. I couldn’t see the point, but I was sure my confusion was an indication that I was in the presence of some deep magic from the dawn of time. I was willing to pay a great deal to be initiated into those mysteries. I had to know.

Fortunately, I found a paying gig before I parted with the loads of cash that it would have required to take that course from those opportunistic ruffians that seemed to want to prey upon naive people that have dreams of becoming professional developers. The thing is, it just doesn’t take a lot of know-how to keep up with the demands of life as a small-time maintenance programmer. The so-called .Net Framework 3.0 came out, and the subsequent marketing blitz failed to get me enamored. It just seemed like a bunch of solutions to problems I didn’t have. I grew enraged at the clunky performance of Visual Studio 2005 and SQL Server 2005 on my piddly little laptop. Service packs and glitzy refactoring tools did little to rekindle my faith in the great high priests at Redmond. I began tinkering with a strange language called Lisp and bizarre text editor called Emacs with every spare moment I could find.

I didn’t get very far at first, but it was really fun to play with it. A lot of people in those circles were talking about some crusty old book called Structure and Interpretation of Computer Programs. Somehow I got convinced to start working through it. I didn’t have to take out a loan or anything. There were even some cool lectures from the eighties to go with them. Many, many hours later, I finally began to get answers to those unanswered questions from the years before: the Delegate was a foreign concept borrowed from other traditions of programming where procedures were first class objects– they could be passed as arguments, stored as variables, anything…. In it’s original habitat, the first-class procedures were very cleanly expressed. When they were imported into C# land, the local instantiaton and declaration rituals required a little more work to set up the same idea. (I personally think that extra verbosity makes it harder to see the point, but that’s just me.)

So assuming you’re comfortable with objects, what exactly are delegates for? They make composition of functionality much easier. Imagine an object with several complex methods that inter-relate. You could set up several properties that could take delegates as their arguments. Suddenly you have everything you need to set up an event architecture. The same class is running everywhere, but each instantiation can be adapted to specific situations with the delegates. Whenever the methods are called and events need to be triggered, the object’s delegates essentially supply pointers to the code it needs to run. And unlike that crappy event code in your goofy Access application, you can reconfigure your events at runtime. This opens up a new level of configurability that can be a big help in setting up your core application architecture or when you need things to be set up slightly different for your test harness or if you want to have different types of output behavior in different situations.

But didn’t we have everything we need with classes and interfaces? Why do delegates have to come onto the scene and crash our object oriented party? Well it does come down to how much configurability you’re going to need. If you’ve got classes that are all going to need their own custom implementation of a method, then interfaces are probably going to be the way to go. But if you can look beyond the noise and see a common theme to all of those classes, you may be able to abstract out the core logic and use delegate functions to initialize the classes. Or you can do both and wire everything under the hood with delegates, and still have a nice complicated object model that makes it look like you’ve contributed a lot to the project. But the way C# is developing, it’s coming down more to a question of how much you like to type. The original syntax for defining delegates was almost as verbose as defining an interface and a class. Anonymous functions cut back on the required number of lines of code, but were a little bit clunky looking. The current iteration with Lambda Expressions is so clean and simple, that it’s hard not to like it. Why use several lines of code and as many curly braces to say what can be done with a single curly-brace free line of beauty?

Here’s some C# 3.0 code to compare several ways to do the same basic thing. (I’ve adapted some of it from Eric White’s post on this topic.) Judge for yourself which is better:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GoFunctional {
  class TestApp {
    //Why can't this be declared in the Main method?
    private delegate int ChangeInt(int arg);

    static void Main(string[] args) {
      //Interface
      DoubleIt dbit = new DoubleIt();
      Console.WriteLine("{0}", dbit.OperateOnInt(5));

      //Standard Delegate
      ChangeInt myDelegate = new ChangeInt(TripleIt);
      Console.WriteLine("{0}", myDelegate(5));

      //Standard Delegate w/out "new"
      ChangeInt myOtherDelegate = TripleIt;
      Console.WriteLine("{0}", myOtherDelegate(5));

      //Anonymous Method
      myDelegate = new ChangeInt(delegate(int arg){ return arg * 4; } );
      Console.WriteLine("{0}", myDelegate(5));

      //Lambda Expression
      myDelegate = arg => arg * 5;
      Console.WriteLine("{0}", myDelegate(5));
      Console.Read();
    }

    static public int TripleIt(int arg) {
      return arg * 3;
    }
  }

  interface iIntMethod {
    int OperateOnInt(int arg);
  }

  class DoubleIt : iIntMethod {
    public int OperateOnInt(int arg) {
      return arg * 2;
    }
  }
}
Advertisements

10 Responses to “If You Want to Understand C#, Then Don’t Waste Time Studying C#: Delegates vs Interfaces in a Nonfunctional World”

  1. dan Says:

    Different tools for different jobs. One example being event handling in a form. How would you handle the OnClick action of two button within a form using interfaces?

  2. lispy Says:

    That’s not quite a fair question. Haven’t the designers of the form class made that decision for us already?

  3. Chii Says:

    why cant microsoft call a function a function, instead of calling it a Delegate! its…confusing …i got heaps confused by it the first time i saw it.

  4. lispy Says:

    This is completely off the cuff, but I think the name “delegate” signals that OOP is still the primary worldview of the language in spite of the functional elements that are creeping in. The class definition is where the focus is and normally specifies its own methods. But with delegates, the class can, uh… you know… delegate responsibility for supplying/defining methods to the person that uses the class.

    Keep in mind that there technically aren’t any functions in the language. There’s methods that return values and void methods that don’t. “Functions” are what the vb crowd calls them. You know that while there are probably some nice pedantic reasons for why we should avoid misappropriating mathematical terminology, we cannot under any circumstance let those throbbing masses of ignorant coders in on the joke.

    Welcome to the conspiracy, Chii.

  5. Aaron Davis Says:

    Three points:
    1) Your question at line eight was probably rhetorical, but I will answer anyway. You are declaring an inner class, not an instance. Inner classes, structs, and enums have to happen inside the class.
    2) The Anonymous Method version is longer than it needs to be. Delegates only care about the signature. You could have left the off the call to new ChangeInt and just used the delegate. I think the syntax you are using is a hold-over from the 1.1 days, when they didn’t have anonymous delgates, so the only way to use the functionality was new Delegate(MyMethod).
    3) I may just have missed it, but I don’t see the myDelegate variable defined. If you are defining in place, then you need to put var in the anon delegate version (I think), and Func before the lambda expression version.

  6. dan Says:

    I think it’s a fair comment, delegates were used because they are a natural fit for event handling. Like I said, different tools for different jobs.

  7. mike Says:

    Great blog! I have read a few of your posts and I feel a sense of kinship.

    I agree with your take on .NET Delegates. Every time I use them I have to re-familiarize because they are so odd.

    I would like to make a few observations if I may. As mentioned, Delegates are just function pointers on steroids. Back in the 1990s, Windows application developers, programming in C, became familiar with the concept of a ‘call-back function’.

    At the bowels of every Windows program, there is a main window and the main window has a call-back function known as the WndProc. Be assured that even today there are WndProcs, they are just buried under a mountain of abstraction.

    Call-backs appear in numerous APIs (including in the *nix ). One technique that is common across Windows and *nix is to supply a spawning thread with a function that will execute the thread. In Windows vernacular, this is the ThreadProc.

    Along came COM, VB and the C++ frame-works: MFC, and ATL, which provided Object-Oriented abstraction layers but I wonder if the folks at Microsoft felt a little under-powered without the use of thier trusty friend, the call-back function.

    Another more salient point is that VB 4/5/6 and COM used reference counting as a form of garbage collection. In the design patterns infused days of the late 1990s, it was common to see designs with classes that referenced one another, particularly for publisher-subscribe purposes. It was very easy for developers to create structures of classes that would never fully release its references, creating huge memory leaks.

    I think this is what led to .NET’s Disposable pattern and the Delegate. I don’t know this for absolute certain and it wouldn’t be hard to test, but I think registering with a delegate does not have the same implications as maintaining a reference to a class reference. If the only ‘connection’ to a class is in the form of a Delegate subscription, I bet the class is GCed.

    And like the ThreadProc of old, the Delegate absolutely rocks in the realm of asynchronous processing. Probably the only downside is that the developer now has underside the implications of multi-threading, state integrity and the fact that Windows UIs are thread sensitive, one thread cannot talk to a UI running on another thread, it must asynchronously ‘post’ a message to that Window’s message queue, which will in turn, call that window’s call-back function (sorry).

    .NET does provide functionality to handle this (using Delegates of course) but it is a little hairy for the uninitiated. (Don’t you think that this should be built-in some how?).

    Anyway, thats my take on the Delegate thing.

  8. Sadek Drobi Says:

    You do not need to use new ChangeInt() for the anonymous method, you can pass it right away exactly like the lambda expression.

  9. David Bolton Says:

    The funny thing about delegates is that they are just events from Delphi which were being used in 1995! Not really surprising given Anders Hejlsberg, in common. Ok you can have multiple event handlers in C#, that’s new and the lambda functions etc… but at their heart they are still just events!

    David Bolton

  10. Mike Says:

    I didn’t realize there was Delegate/Delphi connection. Very interesting. I learned Delphi 1.0 on Windows 3.x many years ago and was very pleased with it.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: