.NET Double dispatch

In software engineering, double dispatch is a special form of multiple dispatch, and a mechanism that dispatches a function call to different concrete functions depending on the runtime types of two objects involved in the call.

In most object-oriented systems, the concrete function that is called from a function call in the code depends on the dynamic type of a single object and therefore they are known as single dispatch calls, or simply virtual function calls.

Wikkipedia

Blown away ? 🙂 Lets me introduce an example:

public class SaladIngridient
{
}

public class FruitSaladSaladIngridient : SaladIngridient
{
}
    public class Salad
    {
        public virtual void WhatSaladAreYou(SaladIngridient ingridient)
        {
            Console.WriteLine("Salad with with {0}", ingridient);
        }
    }

    public class FruitSalad: Salad
    {
        public override void WhatSaladAreYou(SaladIngridient ingridient)
        {
            Console.WriteLine("Fruit salat with {0}", ingridient);
        }
    }

Now we will test different test cases in order to see how .NET platform respond to defferent cases:

    class Program
    {
        static void Main(string[] args)
        {
            Test1();
            Test2();
            Test3();

            Console.ReadKey();
        }

In Test#1 we will used explicit types for salad and it’s ingredients:

        static void Test1()
        {
            Salad baseSalad = new Salad();
            FruitSalad fruitSalad = new FruitSalad();

            SaladIngridient baseIngridient = new SaladIngridient();
            FruitSaladSaladIngridient fruitIngridient = new FruitSaladSaladIngridient();

            Console.ForegroundColor = ConsoleColor.DarkGreen;
            Console.WriteLine("Test1 - Base salad with different ingredients");
            Console.WriteLine("");
            baseSalad.WhatSaladAreYou(baseIngridient);
            baseSalad.WhatSaladAreYou(fruitIngridient);
            Console.WriteLine("---------------------------------------------");

            Console.WriteLine("Test1 - Fruit salad with different ingredients");
            Console.WriteLine("");
            fruitSalad.WhatSaladAreYou(baseIngridient);
            fruitSalad.WhatSaladAreYou(fruitIngridient);
            Console.WriteLine("---------------------------------------------");
            Console.WriteLine("");
        }

In Test#2 we will used explicit types for salad ingredients but both salads will be define differently than in i first case:

        static void Test2()
        {
            Salad baseSalad = new Salad();
            Salad fruitSalad = new FruitSalad();

            SaladIngridient baseLead = new SaladIngridient();
            FruitSaladSaladIngridient derivedLead = new FruitSaladSaladIngridient();

            Console.ForegroundColor = ConsoleColor.DarkYellow;
            Console.WriteLine("Test2 - Base salad with different ingridients");
            Console.WriteLine("");

            baseSalad.WhatSaladAreYou(baseLead);
            baseSalad.WhatSaladAreYou(derivedLead);

            Console.WriteLine("---------------------------------------------");

            Console.WriteLine("Test2 - Fruit salad with different ingridients");
            Console.WriteLine("");

            fruitSalad.WhatSaladAreYou(baseLead);
            fruitSalad.WhatSaladAreYou(derivedLead);

            Console.WriteLine("---------------------------------------------");
            Console.WriteLine("");
        }

In Test#3 either salads and ingredients will be defined more “generic” than in previous cases:

        static void Test3()
        {
            dynamic lead = new SaladIngridient();

            Salad baseSalad = new Salad();
            Salad fruitSalad = new Salad();

            SaladIngridient derivedLead = new FruitSaladSaladIngridient();

            Console.ForegroundColor = ConsoleColor.DarkRed;
            Console.WriteLine("Test3 - Base salad with different ingridients");
            Console.WriteLine("");

            baseSalad.WhatSaladAreYou(lead);
            baseSalad.WhatSaladAreYou(derivedLead);

            Console.WriteLine("---------------------------------------------");

            Console.WriteLine("Test3 - Fruit salad with different ingridients");
            Console.WriteLine("");

            fruitSalad.WhatSaladAreYou(lead);
            fruitSalad.WhatSaladAreYou(derivedLead);

            Console.WriteLine("---------------------------------------------");
            Console.WriteLine("");
        }

The output will be:

Test1 - Base salad with different ingridients

Salad with with DynamicExample.SaladIngridient
Salad with with DynamicExample.FruitSaladSaladIngridient
---------------------------------------------
Test1 - Fruit salad with different ingridients

Fruit salat with DynamicExample.SaladIngridient
Fruit salat with DynamicExample.FruitSaladSaladIngridient
Test2 - Base salad with different ingridients

Salad with with DynamicExample.SaladIngridient
Salad with with DynamicExample.FruitSaladSaladIngridient
---------------------------------------------
Test2 - Fruit salad with different ingridients

Fruit salat with DynamicExample.SaladIngridient
Fruit salat with DynamicExample.FruitSaladSaladIngridient
Test3 - Base salad with different ingridients

Salad with with DynamicExample.SaladIngridient
Salad with with DynamicExample.FruitSaladSaladIngridient
---------------------------------------------
Test3 - Fruit salad with different ingridients

Salad with with DynamicExample.SaladIngridient
Salad with with DynamicExample.FruitSaladSaladIngridient
---------------------------------------------

If you follow output very carefully, you will find that there is problem in Test3() function. Fruit salad not being called anymore, but it’s base class.

Before rushing to fix it, let’s stop here and try to analyze what happened so far and why ?

When you have an object that calls virtual function:

baseSalad.WhatSaladAreYou(derivedLead);

baseSalad object will be determined in a run time. But function that will be called will be determined by parameter (in this case derivedLead) in a compile time. It is VERY important to understand!

Explanation for this behavior in short would be: Parameter will determine which function to run in compile time by static type resolution (basically by its declaration type, which is Salad in this case) and not by new FruitSalad.

How to solve: We can solve it by dynamic binding resolution or Double dispatch. The idea is instead of identify type of object in compile type, identify it in runtime.

Dynamic binding resolution:

So Test#3 should look like following:

        static void Test3()
        {
            dynamic lead = new SaladIngridient();

            Salad baseSalad = new Salad();
            Salad fruitSalad = new Salad();

            dynamic derivedLead = new FruitSaladSaladIngridient();

            Console.ForegroundColor = ConsoleColor.DarkRed;
            Console.WriteLine("Test3 - Base salad with different ingridients");
            Console.WriteLine("");

            baseSalad.WhatSaladAreYou(lead);
            baseSalad.WhatSaladAreYou(derivedLead);

            Console.WriteLine("---------------------------------------------");

            Console.WriteLine("Test3 - Fruit salad with different ingridients");
            Console.WriteLine("");

            fruitSalad.WhatSaladAreYou(lead);
            fruitSalad.WhatSaladAreYou(derivedLead);

            Console.WriteLine("---------------------------------------------");
            Console.WriteLine("");
        }

Now the object type does not known in compile time. When code will run, technically it should throw something like “function not found”, but thanks to the Dynamic Binder it will bind to the function in our FruitSalad class in a run time.

Leave a Reply

Your email address will not be published. Required fields are marked *