Skip to main content

Extension Methods - A Polished C++ Feature !!!

Extension Method is an excellent feature in C# 3.0. It is a mechanism by which new methods can be exposed from an existing type (interface or class) without directly adding the method to the type. Why do we need extension methods anyway ? Ok, that is the big story of lamba and LINQ. But from a conceptual standpoint, the extension methods establish a mechanism to extend the public interface of a type. The compiler is smart enough to make the method a part of the public interface of the type. Yeah, that is what it does, and the intellisense is very cool in making us believe that. It is cleaner and easier (for the library developers and for us programmers even) to add extra functionality (methods) not provided in the type. That is the intent. And we know that was exercised extravagantly in LINQ. The IEnumerable was extended with a whole lot set of methods to aid the LINQ design. Remember the Where, Select etc methods on IEnumerable. An example code snippet is worth a thousand words:-

static class StringExtensions
{
   /// 
   /// 'this' decorator signifies that this is an extension method.
   /// It must be appear only on a public static method.
   /// Such a method is added to the public interface of the type following 
   /// the 'this' decorator.
   /// 
   public static int ToInteger(this string s)
   {
       return Convert.ToInt32(s);
   }
   
   public static string Left(this string s, int position)
   {
       return s.Substring(0,position);
   }
   
   public static string Right(this string s, int position)
   {
       return s.Substring(s.Length - position);
   }
}

You might be aware of all this hot news. But our topic of the day is neither Extension Methods nor LINQ. It is something that dates back to C++. And you will see at the end of this post that extension methods are a polished version of a C++ principle. Ok, let us try to read some code:-

int Add(SomeClass& sc, int x)
{
   // Let us get to here a little later.
}

class SomeClass
{
private: int m_nNum;
public: void SomeMethod(int n);
public: int Num const
   {
      return this->m_nNum;
   }
};

The code is simple - We have a class called SomeClass and a global function. The global function takes a SomeClass instance by reference and an integer by value. The intent of the function is to add x with m_nNum. But whether to save it to m_nNum or just return is a topic we will deal in a little while. But do we understand that the Add function and SomeClass are closely related ?

There are two principles to know in C++ to understand the relation.

Interface Principle

For a class X, all functions, including free functions, that both (a) "mention" X, and (b) are "supplied with" X are logically part of X, because they form part of the interface of X.

* Supplied with X means that the function is provided (distributed with) in the same header file as X.

So now, Add mentions SomeClass and (to keep the discussion short assume that it) is supplied with SomeClass. If that, then Add is a part of the public interface of X. That should convince you.

Koenig Lookup

When an unqualified name is used as the postfix-expression in a function call, other namespaces not considered during the usual unqualified lookup may be searched, and namespace-scope friend function declarations not otherwise visible may be found. These modifications to the search depend on the types of the arguments. Those are lines from the C++ standard and must be tough to understand like the verses in the Bible. So let us talk our language to understand that:

namespace CPP
{
     class SomeClass { };
     void Foo(SomeClass);
}

CPP::SomeClass sc;

void main() 
{
     Foo(sc);
}

Will you be still surprised that Foo(sc) call will link to the CPP::Foo ? Don't be. That is what the cryptic lines above talks about. Ok, one more example:

namespace CPP
{
   class SomeClass { };
}

void Foo(CPP::SomeClass);


void main()
{
   CPP::SomeClass sc;
   Foo(sc); // Got it ?
}

So now down to my point, Extension Methods is a polished version of the Interface Principle (or Koenig Lookup) in C++. The facility has been in C++ for a long time but not sure if exercised well (and wisely). Had the intellisense been intelligent enough, C++ would claimed it a mighty feature. Since the C++ IDE has been the same sucking way for a long time now, C++ got the wrong outlook - a hard programming language.

Hey C#, No hard feelings. It is just a perspective. Either way, My compiler compiles your compiler.

Comments

Anonymous said…
Senthil Kumar - 26 APR 2008 4:00 PM
Interesting view, and they are similar in the sense that both of them only affect how the compiler looks up a matching method. But in my opinion, the biggest advantage, and the reason for existence of extension methods is that you can call them with the object.method() syntax. Granted, it's syntactic sugar and the compiler simply translates that to the static method call, but it allows code to flow much more naturally.

Also, extension methods are the only way you can add methods to instantiated generic types - you could, for example, add a SumOfAll method to List only.
Unknown said…
Vivek Ragunathan - 05 MAY 2008 11:01 AM
Templates and Generics are not fit for comparison. So besides your 'SumOfAll' statement, I guess the (V)C++ folks could have done a better job with the compiler. The C++ compiler even to this day seems to be a giant complex parser upgraded to C++ itself from BASIC or assembly language. While in the right means, it must have been much more powerful and super-intelligent providing a lot of something like 'Compiler Services'. Well a poor kid (C++) has to look up to a rich kid (C#).
Anonymous said…
Bryan Lee - 31 JAN 2009 00:44 AM
Just want to say that I like your comment about "My compiler (C++) compiles your compiler (C#). Straight to the heart!
Anonymous said…
The post misses the essential point of extension methods (though it touches on it at the end): namely, tooling support. Yes, extension methods are really only syntactic sugar. But many language enhancements these days can be similarly dismissed. One wonders why language designers would go to such pains to create something so "superficial". The answer is that such syntactic enhancements are a tremendous boost to productivity. The simple technique of inverting the ordering of a function and its first argument is profound. If I begin with a function that is part of the (ADL-determined) interface of a class, I have no scope within which to automatically determine its first argument (a value/reference/pointer to an instance the given class). However, if I begin by typing that class instance, modern tools (e.g., intellisense) can present and automatically complete all methods/properties/events on that interface, including those determined by ADL. Just because C++ does not currently offer extension methods, does not imply that they wouldn't be a valuable addition to the language. Who would have imagined a few years ago that C++ would now have support for lambdas (another bit of syntactic sugar)?
Unknown said…
I did not mean to dismiss the excellent language features in C#. Instead wanted to point out that such features could have been brought in C++ along with intellisense and tooling support. Imagine how long it took lambdas to incorporate into C++ while they predate C++. C++ could have even more productive.
Anonymous said…
really?
Anonymous said…
FYI, "main" should always return an "int", never "void" (it's illegal)

Popular posts from this blog

Implementing COM OutOfProc Servers in C# .NET !!!

Had to implement our COM OOP Server project in .NET, and I found this solution from the internet after a great deal of search, but unfortunately the whole idea was ruled out, and we wrapped it as a .NET assembly. This is worth knowing. Step 1: Implement IClassFactory in a class in .NET. Use the following definition for IClassFactory. namespace COM { static class Guids { public const string IClassFactory = "00000001-0000-0000-C000-000000000046"; public const string IUnknown = "00000000-0000-0000-C000-000000000046"; } /// /// IClassFactory declaration /// [ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid(COM.Guids.IClassFactory)] internal interface IClassFactory { [PreserveSig] int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject); [PreserveSig] int LockServer(bool fLock); } } Step 2: [DllImport("ole32.dll")] private static extern int CoR

Passing CComPtr By Value !!!

This is about a killer bug identified by our chief software engineer in our software. What was devised for ease of use and write smart code ended up in this killer defect due to improper perception. Ok, let us go! CComPtr is a template class in ATL designed to wrap the discrete functionality of COM object management - AddRef and Release. Technically it is a smart pointer for a COM object. void SomeMethod() { CComPtr siPtr; HRESULT hr = siPtr.CoCreateInstance(CLSID_SomeComponent); siPtr->MethodOne(20, L"Hello"); } Without CComPtr, the code wouldn't be as elegant as above. The code would be spilled with AddRef and Release. Besides, writing code to Release after use under any circumstance is either hard or ugly. CComPtr automatically takes care of releasing in its destructor just like std::auto_ptr . As a C++ programmer, we must be able to appreciate the inevitability of the destructor and its immense use in writing smart code. However there is a difference