Simplifying code with anonymous methods

One of the easiest ways to avoid writing and having to maintain duplicate code is to use an anonymous method or anonymous function. For example, I recently ran across some code that was validating dates in a UI application, and reporting errors if the dates were out of range. The code looked something like this:

    void DoStuff(MyModel model)
    {
        if (model.StartDate < DateTime.UtcNow)
        {
            var dt = ConvertUtcToLocal(model.StartDate, model.TimeZone);
            AddErrorMessage("Start Date " + dt.ToString("M/d/yy h:mm tt") + " is out of range.");
        }
        if (model.EndDate < DateTime.UtcNow)
        {
            var dt = ConvertUtcToLocal(model.EndDate, model.TimeZone);
            AddErrorMessage("End Date " + dt.ToString("M/d/yy h:mm tt") + " is out of range.");
        }
        // six more similar date/time validations
    }

Our client asked that the format be changed. Which meant going through and changing the format in eight different places. In the process I found two bugs in the code, both obvious copy-paste errors.

With a little bit of thought, the programmer who wrote this (or the last programmer to modify it) could have simplified things quite a bit and in the process made errors much less likely to occur. How? By creating an anonymous method that does the validation and error message formatting:

    void DoStuff(MyModel model)
    {
        var validateAndReport = new Action<string, DateTime>((fieldName, dt) =>
        {
            if (dt < DateTime.UtcNow)
            {
                var localDate = ConvertUtcToLocak(dt, model.TimeZone);
                AddErrorMessage(fieldName + " " + localDate.ToString("M/d/yy h:mm tt") + " is out of range.");
            }
        });
        
        validateAndReport("Start Date", model.StartDate);
        validateAndReport("End Date", model.EndDate);
        // etc.
    } 

Programmers are often hesitant to add simple methods like this outside of their functions because they think it pollutes the namespace, and they often require passing a bunch of parameters for context. Anonymous methods solve both problems: they’re invisible outside of the containing method, and they have access to all of the context that the containing method has access to. With this technique I ensure that all of the dates are formatted correctly, and I can modify the formatting by changing just one line of code. In addition, there are many fewer lines of code and they’re much easier to understand.

The only drawback I see is that programmers have to learn something new: “We can’t use this Action thing! Other programmers won’t understand it!” (Yes, somebody did say that to me.) Tough. Things change. To me and most other programmers I know, the modified code is clearly superior to the old code in every way that matters. I realize that there are some performance implications and hidden memory allocations involved. A few small allocations and a few microseconds aren’t going to make a difference in this code, or any other code in the project.

C# 7.0 introduced local functions: the ability to create a function within a function. This is more than just syntactical sugar around the anonymous function shown above. The local function still can capture local variables, but it avoids the allocation and slight performance hit of the anonymous method. The code above, if written to use a local function, would look something like this:

    void DoStuff(MyModel model)
    {
        void validateAndReport(string fieldName, DateTime dt)
        {
            if (dt < DateTime.UtcNow)
            {
                var localDate = ConvertUtcToLocak(dt, model.TimeZone);
                AddErrorMessage(fieldName + " " + localDate.ToString("M/d/yy h:mm tt") + " is out of range.");
            }
        };
        
        validateAndReport("Start Date", model.StartDate);
        validateAndReport("End Date", model.EndDate);
        // etc.
    }

Unfortunately, I’m not yet using C# 7.0, so I can’t take advantage of this new feature. I’m also unable to find the official language specification for version 7. However, the article Thoughts on C# 7 Local Functions gives some good information about how it works.

1 comment to Simplifying code with anonymous methods

  • Dennis Clark

    I think what you are encouraging is “use the DRY principle”, more than “use anonymous methods”. I actually bump code back from reviews for coding too much into anonymous lambdas. In your case Jim, you actually assigned your action a local variable with a name, so it isn’t technically “anonymous” really, right? Nor are local functions, since you have to given them a name also. So while I think you’re doing and encouraging a good thing, I wonder it you meant to be encouraging the use of named operations, not actually anonymous ones.

    Truly anonymous functions (or basically, complex lambdas, nested lambdas, etc) in linq expressions can make those expressions very difficult to understand. Programmers write them partly out of narcissistic, self-congratulatory syntaxophilia, and partly out of laziness, because admittedly good naming can truly be a very hard thing to do. You see this all the time with linq examples posted internet. Big, tricksy write-only linq statements, spanning far too many lines with far too many indentations and nested parens and brackets. Why? Because it lets them skip the naming parts. And maybe just to appear clever too, perhaps.

    So sure naming is hard, but without a meaningful name, it can be very hard for anyone else looking at a given expression to understand intent. Just like in your example, it can be hard to understand whether those expressions contain a defect or not. So I make my developers practice DRY, but I also specifically discourage them from using anonymous methods unless they are truly simple and easy to understand at a glance.

    We use the new C#7 local functions in our codebase. Sure, they are basically the syntactic sugar equivalent of actions or funcs, which have been around a long time. To me the most important aspect of them is that they require you to think about giving your operation an actual name, to replace an operation that is otherwise anonymous. ReSharper will also point out the opportunities to apply this new syntax, generally with a suggested name that is often pretty good. Like locally declared actions or funcs, they’re basically fine as long as they’re small.

    Above a certain size though, local functions clutter their containing scope. They remind me of Pascal programming, in which you can basically write your whole program as one function that just contains more and more deeply nested function bodies leading to methods that to complex and span way too many lines. If they do that, they are not helping–probably best to move them into a class private method.

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

  

  

  

Categories

A sample text widget

Etiam pulvinar consectetur dolor sed malesuada. Ut convallis euismod dolor nec pretium. Nunc ut tristique massa.

Nam sodales mi vitae dolor ullamcorper et vulputate enim accumsan. Morbi orci magna, tincidunt vitae molestie nec, molestie at mi. Nulla nulla lorem, suscipit in posuere in, interdum non magna.