12/17/07

Delegates as an alternative to single-method interfaces

I noted some time ago that one can use delegates instead of interfaces that contain one method. In fact, I think delegates are more flexible when compared to single-method interfaces and I'll try to explain why.


The scenario

As a reminder, the discussion started with this post: Making ICollection inherit from more fine-granular interfaces. What was the problem? I wanted to design a method that adds a large amount of data to some collection. The method would possibly serve all sorts of different clients (callers). A very reusable solution would be to just return the items so that they can be added by the client (on the caller's side), but that would mean:

  • Clients have to do additional work of adding the items to their collections (duplication of code with the same intent)
  • This also costs at least double performance (each element is first put into a temporary storage, and then put into the target storage, which gives us O(2n))
  • The method had to accumulate the items before returning them (O(n) memory consumption for the returned values (List<T>, ReadOnlyCollection<T> or whatever)
  • Even in case of yield return, where O(1) temporary storage for return values is required (values are being returned lazily one-by-one as they are needed), you'd still have to add those values to the target collection, sooner or later

That's why I decided to go for a void method that accepts a collection where to add the items (to avoid performance penalties). My first implementation accepted the ICollection<T>, the .NET framework's most probable candidate for a thingy that has an 'Add' on it. However, ICollection<T> is not good enough, because not all the types that have 'Add' on it implement ICollection<T>. There was some buzz on the blogosphere about duck-typed implementation of collection initializers in C# 3.0 - a good example of a place where we definitely lack the ISupportsAdd<T> interface or something like this.


The Solution with Delegates

To make long story short, here's a what I think a good solution to the problem. Instead of having the interface:

interface ISupportsAdd<T>
{
void Add(T item);
}
it is enough to use the System.Action<T> delegate. Compare the old way and the new way:
void OldAdd<T>(ISupportsAdd<T> collectionToFill)
{
collectionToFill.Add(item1);
// ...
collectionToFill.Add(item100);
}

void NewAdd(System.Action<T> addMethod)
{
addMethod(item1);
// ...
addMethod(item100);
}
And on the caller's site:
// The target collection can be anything
// that has an "Add" method
// (which can even be named differently)
List<int> resultsToFill = new List<int>();

// Don't pass the entire collection
// when you are only going to use
// the Add method anyway!
// Only pass the Add method itself:
NewAdd(resultsToFill.Add);

See, that easy. Just pass the "pointer" to the Add method of your choice and the NewAdd method will call it as many times as there are items!

The important lesson I've learned from this: to make a piece of code reusable (in this case, a method), one should only provide as little information to it as it is necessary.

Earlier I tried to do that subconsciously by demanding more "fine-granular" interfaces - only to provide as little information about the type as necessary (we were not going to use Remove() anyway, so why provide it?).


Delegates - "interfaces on a member level"

Now I've realized, that in case where you only need to use one method, you can go even more granular - no need to pass the type, just pass a member (members are more fine-granular than types). See how it already starts to smell a little like duck-typing? You don't have to declare a necessary interface, your existing type signature is just fine, as long as you provide the necessary member. This is an awesome bonus feature in C#. Unfortunately, it is only limited to one member, and even more, that member has to be a method! (No delegate properties, pity, isn't it?)


Delegates vs. single-method interfaces

To summarize, there has been ongoing talk in the blogosphere about adding an implementation of an interface to an existing type without changing the type itself. There is a desire to automatically or manually make the type implement some interface, as soon as it has all necessary members with the right signatures. C# currently offers a solution, but only if your "interface" consists of exactly one method - you can then use a delegate to that method and pass it around. Delegates in this case are semantically equivalent to single-method interfaces - you can pass around both and you can call both. But delegates are more flexible, because you can take a delegate ("pointer") to an existing type (its method actually) without changing it, and you can't make an existing type implement your interface without changing it.

12/8/07

DG 1.0 - free Dynamic Geometry Software for kids

Dynamic geometry is a piece of software for exploring interactive math constructions directly on your screen. It lets you create any ruler-and-compass constructions using your mouse or stylus. It also allows you to play and experiment with the drawing using drag-and-drop (this is not possible on paper).

 

 

The points in the drawing are actually draggable - as you drag a point, the triangle will change with the rest of the construction. You can create hyperlinked and commented interactive documents:

and live measurements:

 

Download

If you're interested (or you have kids who currently study geometry), you can download DG 1.0 from my website: dg.osenkov.com. The software is free and no setup is necessary, just unzip the archive to any folder and run Geometry.exe. Please let me know if you have any questions or feedback, I'd be happy to help.

 

A bit of history

For the curious ones, DG is a piece of software I wrote in 1999-2002 when I was working for the Kharkiv pedagogical university in Ukraine. A great team of teachers, methodologists and mathematicians worked on this software package, which includes more than 250 interactive drawings to support the school geometry course. I was the only programmer on the project with about 5 PMs and 5 testers :) It is great to know that DG is still being used in many ukrainian schools in geometry lessons, after we shipped the software in summer 2002. The idea of dynamic geometry dates back to 1980's, there are many dynamic geometry programs, so I'm not saying we invented anything new. But we implemented DG to specifically suit the needs of ukrainian teachers and students, and it also turned out to be a pretty good piece of software for everyone else to use. So I decided I'd blog about it, so maybe it could be of some use to someone.

 

Although it has been more than 5 years after we shipped DG, I still sometimes receive feedback from teachers. I'm always happy to see anyone using DG, because I put a lot of soul and effort into this project at that time. Thanks to this project, I grew from being a geeky teenager that I was in 1999 into an experienced developer who shipped and deployed working and tested software in 2002 that still works in 2007 :) I'm very thankful to our project leader, Sergey Rakov, who I also respectfully consider my personal Teacher.