Overblog Suivre ce blog
Editer l'article Administration Créer mon blog
1 mai 2011 7 01 /05 /mai /2011 12:17

 

 

Hi, I am going to review the facilities provided by most object-oriented languages to add some methods to a type without subclassing nor accessing its inner implementation details. You can think of it as alternatives to the Adapter design pattern.

Let's say I have a type T and want to add a method to this type. For demonstration purposes, I will add a method called “universe” that will output the integer 42, which is, as Douglas Adams fans may know, the answer to life, universe and everything. Of course, in a real life program, one will add some more useful methods.

C#

 

C# provides something called “Extension methods”. These are simple public static methods in public static classes that take a first parameter with the this keyword.

 

 class T
{

// implementation of T...
}
public
static class Ext
{

public static int universe(this T t)
{
return 42;
}
}

 

Then one may call the universe method as if it was part of the T class :

 T t = new T();
int
i = t.universe();

One could notice that we get rid of any mention of the Ext class. It is only here because of the dotnet limitation that forbids global functions. Every method must belong to a class.

 

D

 

D provides a simple yet powerful mechanism called Uniform Function Call Syntax (UFCS). Basically, any function f(a[, ...]) can be rewritten as a.f([...]).

 

 class T
{
// implementation of T
}

int
universe(in T t) pure nothrow
{
return 42;
}

T t = new T;
t.universe();

 

This is much simpler than C# Extension methods and more powerful as it does not only applies to classes or structs, but also to built in types. Andrei Alexandrescu used them on built-in arrays to get them the Range interface he had defined for containers (see std.array and std.range D modules for more information).

Objective-C

 

Objective-C provides a way to add methods at runtime to an existing class without subclassing. This is called “categories”.

 

 @interface T : NSObject
{
// T fields
}
// T methods
@end
@implementation
T
// implementation of T methods
@end

// Add a new Category of T with a universe method
@interface
T (Universal)
- (int) universe;
@end

@implementation
T(Universal)
- (int) universe
{
return 42;
}
@end


// all the instances of T in the process now have a universe method
T* t = [[ T alloc] init];
int i = [ t universe ];

Python

 

Python being dynamic, it is very simple to add methods and fields to a class using the built in setattr function :

 

 class T:
pass

def
addUniverseToAClass(aClass):
def func(self):
return 42
setattr(aClass, "universe", func)

t = T()
addUniverseToAClass(T)
i = t.universe()

Java

  System.err.println(“I'm afraid I can't let you do that, Dave.”); // HA-HA ! 

 

Purpose

 

At this point, some of you may ask what is the point of doing all this ? These techniques can be very useful when doing some generic programming. Suppose you have written a very nice generic algorithm that works well with your types. And then someone provides you a new class that has similar abilities but a slightly different interface. Why would you subclass this new type ?

Inheriting a class creates a strong bind between a base class and its offspring that can later have consequences on the evolution of your code base. As you may have noticed, except Python, none of the programming languages presented here supports multiple inheritance...

Partager cet article

Repost 0
Published by Olivier - dans Programmation
commenter cet article

commentaires

Présentation

Recherche

Liens