lamda

Delegates and Lambdas

I’m getting into really understanding about delegates and thought I’d share my thoughts around this. I’m just touching the surface, but event driven development is something I’ve wanted to do for sometime. In this basic tutorial I’m trying to address the following simple problem.

“I would like to work out if one value is greater or less than another”

So this is easy, right? Just plug these methods in


public bool IsGreater(double firstValue, double secondValue)
{
  return ( firstvalue > secondValue);
}

public bool IsLessThan(double firstValue, double secondValue)
{
  return ( firstvalue < secondValue);
}

The really bright ones could do it in one method but what if I wanted to define the operator at runtime or I wanted to store the business logic around how the first and second values interact with each other in a separate place to help code maintainability?

Delegates are what you need.

There are plenty of explanations around what delegates are which are probably much better than mine but here is my take on them. Part of the reason why I didn’t get delegates for sometime is around how much .net hides from you when you start developing.

Here are a few explanations I’ve seen recently
– Delegates are a pipeline through which data can move from one place to another.
– Delegates convert a method into a type or class and wrap around this method ie promote a method to act like a class or assign a pointer to a method.
– Delegates allow some other method to manage the data within the initial object. You are offloading or delegating responsibility of logic to another part of the programme. (hence the word delegation).
– Delegates don’t change data per se, they just help something else (eg another method in another object) manage how they are manipulated but the send and return types must be the same for all implemented methods.
– If you know Interfaces, Delegates are to Methods as to what Interfaces are to Classes.
– Delegates need a start point, an invoker (creator) and an end point which can be in separate classes.

They are essential in Events which are a type of custom delegate which returns void and takes an object (sender) and another container class called EventArgs which can be used to carry extra information. Event are another topic altogether but are fundamental and evolve from knowledge around delegates.

Lambdas

I think just the word Lambda shied me away from them. I had ideas of Greek notation and complex explanations around how Lambdas work but here is my one liner take on Lambdas

Lambdas are a short hand notation to create in line code of delegate method calls

As with all things, they can get quite complex especially when you start using LINQ but just have the above concept in mind. I thinks this is best described in an example, and for you to understand we need to work a bit backwards.

Defining your Pipeline/Delegate

Taking the above example I want to create a pipeline/delegate which will take 2 values and return true or false, what I do with the values is up to me but the actual data moving back and forth will be 2 doubles through and a bool back. So you’d define your delegate like this


public delegate bool OperatorHandler(double ValueFromExternalSource
                                    ,double ValueToCompare);

I’m telling the compiler this delegate/pipeline will take 2 doubles and return a bool

So I’ve turned my method into a class or type and whenever I need to activate the pipeline I need to new the delegate.

End Point

So I have this data running down the pipeline, in the above example I’d like to handle this data and do something with it. I want to have 2 scenarios: one where I’m looking to see if one value is greater than the other and the second to see if one value is less than the other.

I have the option to invoke 2 types of delegates which both take the same data (2 doubles) and return a bool. One will see if it’s greater and other if it’s less than.

    public class OperationRulesHandlers
    {
        public OperatorHandler GreaterThan = (x, y) => { return x > y; };
        public OperatorHandler LessThan = (x, y) => { return x < y; };
    }
 

Here is where we use Lambdas. Let me break this down – I’ve put these delegate handlers or managers in a separate class to show how we can separate out the code. This would form the basis of business layer.

x and y, where did they come from and how does the compiler know what they are? If you noticed the delegate above already has the information to understand what the x and y is. In essence the delegate defines the footprint which takes 2 doubles (double, double) and returns bool so I don’t need to insert the value types. The doubles and bool are inferred from the delegate. We use x and y because we are lazy, we could have easily written it another way.


public OperatorHandler GreaterThan = (ValueFromExternalSource, ValueToCompare) 
=> { return ValueFromExternalSource > ValueToCompare; };

public OperatorHandler LessThan = (ValueFromExternalSource, ValueToCompare) 
=> { return ValueFromExternalSource < ValueToCompare; }; 

– within the squiggly braces are the in line method. It’s just short hand for the following bit of code.

 {    
    if (x > y)
    {
        return true;
    }
    else
    {
        return false;
    }
}

Start Point or Invoking

So we need a method which actually passes the values. In this examples I’ve wrapped it in a class.


  public class ProcessData
  {
      public bool IsValueTrue(double externalValue, double compareValue
                             ,OperatorHandler operation)
      {
          return operation(externalValue, compareValue);
      }
  }

Notice how we are treating the Delegate like a method and passing the 2 doubles to return a bool. The beauty of this code is that the OperatorHandlers handle the logic and depending on which type I instantiate will depend on whether there is a greater or less than operation performed on the 2 doubles. I’m thus managing how the values are manipulated at run time.

I then invoke the delegate with associated values to process with the following lines from my Main Class.


 ProcessData data = new ProcessData();

 bool isTrueForGreater=data.IsValueTrue(1.0,2.0,
                       new OperationRulesHandlers().GreaterThan);

 Console.WriteLine(String.Format("Is 1.0 greater than 2.0
                    --> Answer : {0}\n", isTrueForGreater));

Enclosed is the final code

    namespace DelegatesExample
    {
        public delegate bool OperatorHandler(double ValueFromExternalSource
                                           , double ValueToCompare);

        public class Program
        {
            static void Main(string[] args)
            {
              ProcessData data = new ProcessData();

              bool isTrueForGreater=data.IsValueTrue(1.0,2.0,
                                    new OperationRulesHandlers().GreaterThan);

              Console.WriteLine(String.Format("Is 1.0 greater than 2.0
                                               --> Answer : {0}\n", isTrueForGreater));

              bool isTrueForLesser=data.IsValueTrue(1.0,2.0,
                                   new OperationRulesHandlers().LessThan);

              Console.WriteLine(String.Format("Is 1.0 less than 2.0
                                               --> Answer : {0}", isTrueForLesser));
              Console.ReadLine();
            }
        }

        public class OperationRulesHandlers
        {
            public OperatorHandler GreaterThan = (x, y) => { return x > y; };
            public OperatorHandler LessThan = (x, y) => { return x < y; };
        }

        public class ProcessData
        {
            public bool IsValueTrue(double externalValue, double compareValue,
                                    OperatorHandler operation)
            {
                return operation(externalValue, compareValue);
            }
        }
    }

So the sequence above is
– Define the delegate/pipeline
– create the delegate (new OperationHandlers..)
– pass the delegate with required values to another class (data.IsValueTrue…)
– Invoke the delegate with the parameters required (return operation—)
– The associated method within the Lambda is then used.

Use the debugger to loop through, it’s a good way so see how the compiler moves through the code.

Simple thoughts for simple souls. I hope this triggers others who were in my position to have that light bulb moment of why delegates are useful and like me are journeying in the world of Lambdas.

Photo credit: brian hefele / Foter / CC BY-NC