Do it if you need it – Part 2 – Do it later

In the previous post we looked at wanting to pass in the method for evaluating the operand of a function, rather than passing in the operand itself. We imagined a logicService which might determine if the data is required from a data service to send through an output service. We looked at how to test these.

Now we can look at the options in .NET for implementing this “do it later” approach.

There are two possible reasons that a do-it-later might be required:

1. It’s a callback scenario – we want the algorithm to invoke something of ours when it needs to do something for us
2. We’re saving resources – we don’t want to waste time or memory calculating something we don’t need

So

ConditionalRetriever.OutputIfActiveWithData(logicService, retrievalService.GetBigData(), outputService); 

Isn’t any use, since it gets the data before the function is called.

Method 2 – Interfacing
So what about

ConditionalRetriever.OutputIfActiveWithData(logicService, retrievalService, outputService); 

...

        /// <summary>
        /// The second obvious way of outputting the data - give me the service and I'll pull it when I need it
        /// This sort of breaks encapsulation of calling code, which now needs to provide the service it would like to use
        /// </summary>
        static internal void OutputIfActiveWithDataInterface(ILogicService logic, IDataRetrievalService dataService, IOutputService output)
        {
            if (logic.IsActive())
            {
                string data = dataService.GetBigData();
                output.Output(data);
            }
        }

In this second case (the first being just send the data in), we give the OutputFunction full visibility of the data service which supplies the data. Is this good? Well, yes and no. If you look at the above code, then actually it’s fine it looks like this package could happily use the DataRetrievalService along with the others.

However, we’ve made retrieving the data, and knowing about the source of the data, the concern of this ConditionalOutputter. That MAY be breaking encapsulation. Why should this conditional retrieving/outputting code only work with one source of data? It’s now linked to the IDataRetrievalService. Could there be other ways of getting that data? What if we wanted to conditionally output “GetSmallData” as well as “GetBigData”?

In a lot of cases, the above would work, but for the ILog example from the previous post, it would be horrible. You would need to create a lot of small implementations of an “ILogThis” service for each log message. Yuck!

Method 2 – Delegation
This is the .NET way of saying – “hey, just pass in a function to do it”. Delegates are callable blocks of code that are “somewhere” and can be passed as parameters. They are quite useful for this scenario.

Here is how conditional retriever could be built to enable delegates:

        internal delegate string RetrieveData();
        static internal void OutputIfActiveWithDelegate(ILogicService logic, RetrieveData retrieveMethod, IOutputService output)
        {
            if (logic.IsActive())
            {
                output.Output(retrieveMethod());
            }            
        }

So it has its own delegate type and you just need to provide something which gives it the data when it calls that delegate.

I’m so in love with the lambda syntax of .NET that I implemented my calling code, thus:

ConditionalRetriever.OutputIfActiveWithDelegate(logicService, () => retrievalService.GetBigData(), outputService);

It looks like the first example where we evaluated before the function was invoked, but we’ve just prefixed () => before the code we want. Nice!

Stop there?
I would stop right there. However, I came up with another option. It’s both better and worse. If we use the .NET class Lazy, we get a wrapper around the delegate. This wrapper ensures it’s evaluated at most once. It might well be a nice way to pass around the mechanism for evaluating the operand, without invoking it unless it’s needed. It may even be a good way for this virtual operand to be passed across multiple classes.

        static internal void OutputIfActiveWithLazy(ILogicService logic, Lazy<string> data, IOutputService output)
        {
            if (logic.IsActive())
            {
                output.Output(data.Value);
            }
        }

... 

// invoked:
ConditionalRetriever.OutputIfActiveWithLazy(logicService, new Lazy<string>(() => retrievalService.GetBigData()), outputService);

This last approach involves less code in the class that needs the “do it later” operand, but more code in the places which use it.

I prefer the simplicity of just using a delegate.

So How To Implement Debug Logger?
Have a debug logger wrapper for the logger which has a delegate and decides if to use it.

Old code:

if (myLogger.IsDebugEnabled())
{
   myLogger.Debug(a.GetData() + " is annoying because of " + b.FindSomething());
}

Log wrapper:

public class DebugLogger
{
   private ILog log;
   public DebugLogger(ILog log) { this.log = log; }

   public delegate string ToLog();
   // safely log to debug with no execution/memory overhead unless needed
   public void Debug(ToLog toLog)
   {
      if (log.IsDebugEnabled)
      {
          // invoke the delegate to find out what needs logging
          log.Debug(toLog());
      }
   }
}

// new call site
DebugLogger debugLog = new DebugLogger(myLog);
.
.
.
debugLog.Debug(() => a.GetData() + " is annoying because of " + b.FindSomething());

Nice!

Summary
There are more ways of achieving this, I’m sure. In Java you have anonymous inner classes to implement interfaces, and you’d replace the delegate with a simple one function interface.

In C++ you have function pointers, which don’t answer the question, and functors, which get near.

I’m told Scala does it better.

Overall, though, the solution is probably to use delegates where there’s a lot of calling code that needs to send an operand that may not be evaluated, and to use Lazy for situations where you want to share a potential operand around the system without constructing it until needed.

Advertisements

4 comments

  1. Hi, the pattern is nice, I will keep it in mind, on the other side, when you use a lambda expression, I personally would favor a extension method. Perhaps there is a chance to “simulate” the behaviour with F# and currying, hopefully on the weekend, the sun is not shining 😉

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s