The language feature abuse threshold

C# has an odd strategy to language features which can probably be best approximated with “That looks cool, let’s put it in”. This has resulted in a language which is about as full of syntactic sugar as the very best of them.

As an example, C# now has lambdas since a few years back. They’ve got their own syntax as well. Not that we actually needed lambdas in a strict sense, since we got delegates before that. Not that we needed those either, since we’ve got objects and interfaces to pass around. Which weren’t themselves needed. The only thing you really need is a few machine code instructions. Or, given a convoluted example you need only one assembly language instruction.

Of course you don’t want to code in that, so you’d end up writing in some type of sugar coated language in order to be as productive as possible. But, when are you crossing the threshold of overusing language features just because you can?

My example here is, again, going to be the lambda functions in C#. In part because I am using those myself a lot, and the usage is increasing – maybe in part due to my experience with Haskell which really turned me on to using a functional style.

Local functions

Lambdas let you make local functions, something which isn’t possible using a normal member function. Which means you can create something like this.

public void DoStuff(string message)
{
    Func<string, bool> messageContains = s => (message??"").Contains(s);
    if (messageContains("this"))
    {
        //.. stuff
    }
    else if (messageContains("that"))
    {
        // .. other stuff
    }
}

This saves quite a few characters to type, since you’d get a useful null safe comparison but it’s only scoped in the local function and doesn’t pollute your class. Overuse, or clever?

Self recursive lambdas

This Fibonacci function works just like the standard double recursive function, but from within a local scope.

Func<int, int> fib = null;
fib = f => f < 2 ? f : fib(f - 1) + fib(f - 2);

Granted, this is contrived and probably in all sorts of bad styles? Or appropriate somewhere?

Functions returning functions

My favourite, honestly very very useful, but would you yourself use this? Overuse?

public bool HasSpecificChildren(XDocument doc)
{
    Func<string, Func<XContainer, bool>> hasDescendant = 
        name => e => e.Descendants(name).Any();
    Func<Func<XContainer, bool>, Func<XContainer, bool>, Func<XContainer, bool>> and =
        (a, b) => x => a(x) && b(x);

    return and(hasDescendant("child"), hasDescendant("otherChild"))(doc);
}

In case it’s not obvious, this code is equivalent to this

public bool HasSpecificChildren2(XDocument doc)
{
    return doc.Descendants("child").Any() && doc.Descendants("otherChild").Any();
}

Now, interestingly, though this example is a bit over the top – which of the two implementations is the most redundant. I’d say it is the second one. The lambda sillyness only repeats the functionality once for each part and is actually as factored as you can get. Consider if you were to change the implementation from Descendants to Elements. One solution has only one place to change..

Currying

A final piece of something that probably is a bit from the Haskell world, though interestingly enough the venerable Jon Skeet wrote about it.

Currying is the idea that each function only really needs one argument. This can be achieved in C# as well. Consider this.

public static Func<T1, Func<T2, Func<T3, TResult>>> Curry<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> uncurried)
{
    return a => b => c => uncurried(a, b, c);
}

static void Main(string[] args)
{
    Func<string, string, string, string> func = (a,b,c) => a + b + c;
    var uncurried = func("currying", "is", "awesome");

    Func<string, Func<string, Func<string, string>>> curry = Curry(func);
    var curried = curry("currying")("is")("awesome");
}

This is very rarely seen in C#, but is a mainstay of other languages and can prove very useful indeed for function composition. So, are we abusing the language enough? Or do we need to go even further.

All of the things above have their place in your development toolbox, honestly. But when are you overusing them?

Is it OK to make a local lambda statement in order to avoid passing an argument to a private function? I know I make local lambdas constantly for this very reason. Is it cool to prefer LINQ to avoid making for loops? Should you avoid the var keyword because someone else might get confused of your typing intentions or just go along with the speed of development that it offers constantly?

When are you over the line? And who is to determine what is acceptable?

Advertisements

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s

%d bloggers like this: