Living in the Tech Avalanche Generation

A practitioner’s introspective on technology

Patterns that cross borders - C# to IronPython

Recent consideration of the Template Method Pattern got me to wondering about how I might achieve a little more dynamism with respect to declaration, definition and instantiation when using the template method pattern. Without delving too deep into the “classical” Template Method Pattern it can be described here in code with the most trivial of examples.

C# Classic Template Method Pattern

abstract class FootballMatch
{
    abstract void StartGame();

    abstract void EndGame();

    public virtual void PlayGame()
    {
        Console.Writeline("Players kick the ball around a field");
    }

    public virtual void CompleteMatch()
    {
        StartGame();
        PlayGame();
        EndGame();
        Console.WriteLine("Match completed thanks for attending!");
    }
}

public class AustralianRulesFootballMatch : FootballMatch
{
    public void StartGame()
    {
        Console.WriteLine("Siren blows to begin game….");
    }

    public void EndGame()
    {
        Console.WriteLine("Siren blows to end game….");
    }
}

public class SoccerFootballMatch : FootballMatch
{
    public void StartGame()
    {
        Console.WriteLine("Referee blows whistle to begin game….");
    }

    public void EndGame()
    {
        Console.WriteLine("Referee blows whistle to end game….");
    }
}

 

What about Functions? And how about runtime implementer?

As described above, the implementing classes are defined at design time as concrete derived classes. Doing this in Languages such as Python and Ruby seems a little more flexible in as much that I don’t really require the derivation through an abstract class.

An IronPython Implementation

class RestuarantEndToEndService:

    def __init__(self, servicename, m1, m2, m3, m4):
        self._serviceName = servicename
        self._greetAndQualifyCustomer = m1
        self._takeCustomerOrder = m2
        self._serveTheCustomerMeal = m3
        self._takePayment = m4

    def prepareTheMeal(self):
        print Chef prepares the meal

    def performService(self):
        print Doing %(svc)s Service % {svc : self._serviceName}
        self._greetAndQualifyCustomer()
        self._takeCustomerOrder()
        self.prepareTheMeal()
        self._serveTheCustomerMeal()
        self._takePayment()

def seatCustomer():
    print Greet and seat the customer at their table

def answerOrdersPhoneLine():
    print Answer the phone and take the customer details

def takeCustomerOrder():
    print Waiter / Waitress takes the customers order

def takeCustomerPhoneOrder():
    print Take the customers order by phone

def serveTheCustomer():
    print Waiter / Waitress serves customer their meal

def deliverTheCustomerPhoneOrder():
    print Driver delivers the customers phone order

def takeCustomerPaymentAtCounter():
    print Cashier takes customer payment

def takeCustomerPaymentOnDelivery():
    print Driver takes customer payment

inhouseService = RestuarantEndToEndService(In House,
                    seatCustomer,
                    takeCustomerOrder,
                    serveTheCustomer,
                    takeCustomerPaymentAtCounter)
deliveryService = RestuarantEndToEndService(Delivered,
                    answerOrdersPhoneLine,
                    takeCustomerPhoneOrder,
                    deliverTheCustomerPhoneOrder,
                    takeCustomerPaymentOnDelivery)

inhouseService.performService()
print ***********************
deliveryService.performService()

The DLR, Interop and shifting the code around

What’s a little more interesting is using this pattern in interop scenarios when the templated class is defined in a statically typed language and the template method is supplied by a dynamic language created for the DLR. This can be demonstrated here with the given abstract class and by using my IronPython WPF interactive console control.

public abstract class TemplateClass
{
    public abstract void Operation1();
    public abstract void Operation2();

    /// <summary>
    /// The Tempate Method
    /// </summary>
    public void TheTemplateMethod()
    {
        Operation1();
        Operation2();
    }
}

ip_swap_abstract_from_csharp

Using the Python Help function we can examine the abstract template class and see how it’s been defined. Looking at the printed help on the class it’s clear that the two abstract methods have ‘tagged along for the ride’ as expected. You wont be able to execute them until you provide an implementation, just as you would expect given it’s an abstract class.

ip_swap_abstract_from_csharp_help

The other scenario involves moving some statically typed code (a method) to the IronPython runtime and using an Action / Delegate to  ‘fill in’ the template algorithm in a dynamically typed class. For example in the EndToEndRestuarantService class defined in Python above, we could push the actions (delegates) over from C# to the IronPython runtime. Given a set of Functions defined in managed C#:

var actions = new Dictionary<string, object>();
actions.Add("seat", seat_customer);
actions.Add("order", take_customerOrder);
actions.Add("serve", serve_the_customer);
actions.Add("pay", take_customer_payment_at_counter);

When you push these functions over the Script Scope running the IronPython code, then you can pass those functions around to any other code running within the same scope. With our Restaurant example we can take our named functions from the C# code at runtime and push them into the constructor of our IronPython class:

ip_swap_abstract_from_csharp_func_constructs

When is this pattern useful?

These patterns can be useful in scenarios where you might be considering scripting your managed C# application and providing DLR supported scripting functionality to the application as well. It can also be quite useful when you want to expose some technology that does not currently support full interop (Entity Framework for example) or perhaps you want to make our application model visible to IronPython or IronRuby. There are of course a plethora of patterns that can be implemented in code that can traverse both environments; its really a matter of what we can devise with some imagination.

Share/Save/Bookmark

2 comments

Who becomes the fashion victim amongst the .NET dynamic languages?

A while back I went through the personal struggle of trying to decide which .NET dynamic language I was going to adopt. After some fairly lengthy consideration and with a bit of help from Michael Foord, I chose IronPython. Recently I posed this question to Michael: are .NET developers experiencing some *romantic* attraction to IronRuby? Michael I think was a little taken aback and not sure how to respond, most likely I didn’t frame the question eloquently nor clearly enough and so I will take another shot at it here.

hangersLet me explain what I mean by “romantic”. I am noticing that people (I know) in the .NET development community are leaning more towards IronRuby when faced  with the choice. Perhaps my perspective over the so-called community isn’t broad enough to make any sweeping generalisations here, I understand that, nonetheless, tucked away here in my small corner of the universe I get a sense that I am observing a kind of default (if not romantic and sometimes perhaps envy driven) choice of IronRuby over IronPython.

What are the contributing factors? Some very high profile .NET people have jumped the .NET ship in favour of developing with MRI in the recent past. The most obvious connection I guess may be that ASP.NET developers (who by far number the majority in the .NET employment pool) have an vested interest in the successes of ROR which may account for this perceived phenomenon. I also get the feeling the feeling that Ruby gets a better deal in the hype stakes and that could also be having some impact.

I wonder has anyone else noted this? Figment of my imagination? Way off the beam? One thing is for sure, neither seem to be playing a real part in the commercial world yet; a search on seek.com.au (a well known job market web site) for IronRuby or IronPython or DLR, will sadly produce no results. This is understandable as IronRuby in only just recently gone RC1, but IronPython has been around a little while and some people in some parts of the world do make a living with it already.

UPDATE:

Oh I did forget that perhaps people just think Ruby is the better of the two languages?

Share/Save/Bookmark

1 comment

An IronPython REPL Console in a WPF User Control

Recently I posted an IronRuby Console, purpose built as a WPF user control. The basic reasoning was to allow me drop in scripting into any given application or User Interface. In more recent times (with some help from Michael) I decided to ‘jump ships’ and move to IronPython as my choice DLR language. Given the change in direction I was obviously going to need my console window to support the language of my choosing.

The New IronPython Version

tipas_public_intro

So to move forward with the WPF user control console project I decided to refactor it to support IronPython. Mark has jumped in just recently and started to contribute by adding the new “cached commands”, which offer up / down arrow repeat command behaviour such as found on a DOS console. You will also notice from the screenshot above I have imported the entire System namespace to demonstrate that it is possible (using the environment menu) to print the entire state of the default scopes current set of variables.

Now it’s true I could have done this in a way that allowed for switching between the languages, however I have delayed that decision until IronRuby reaches it’s version 1.0 official release. In the meantime you can now use the IronPython version or the IronRuby Version seperately.

I am going to follow up shortly with an example of how this little window can be become quite useful in a practical way.

Downloads

IronPython Console Window Project

IronRuby Console Window Project

Share/Save/Bookmark

2 comments

Next Page »

Creative Commons Attribution-ShareAlike 2.5 Australia
Creative Commons Attribution-ShareAlike 2.5 Australia