1

This is a generic question about using anonymous functions as arguments to other functions. I give an example in Python, but the question is not about Python (and I'm particularly interested in whether answers might be different for functional languages than for other paradigms).

In Python it is common to pass an anonymous function as an argument to another function, for example:

sorted(my_data_structure, key=lambda x: x[0].foo)

where lambda x: x[0].foo is an anonymous function to return the foo attribute of the 0th element of each thing in my_data_structure (under the assumption that whatever lives in my_data_structure will have a 0th item and that 0th item will have a foo attribute).

To my mind, in all but the simplest cases, this presents a problem for encapsulation and extensibility: what if my_data_structure changes? What if the attribute to sort by becomes bar in a later code refactoring? Now you've got to descend into the actual lambda to deal with it.

Alternatively, this could have been written as:

def my_helper(some_data_thing):
    """My intentions are ____ !
    """
    return some_data_thing[0].foo

#Elsewhere in the code:
sorted(my_data_structure, key=my_helper)

While this adds 4 lines of code, it is more readable. You don't have to parse whatever the lambda is trying to do at the moment you read about the call to sorted. It gives the opportunity for type annotation, documentation, or even unit-testing to occur for the helper function.

If something changes, but you still want the local code around the use of sorted to remain the same, this nicely encapsulates that for you away into the helper function. And if more than one place needed to sort, or group, or whatever, by the same key, you get code reuse better than reproducing the lambda is many locations.

However, others might also say that you are bending over backwards to give a name, my_helper, to a little function that is actually more clear to just see it in code directly.

I can agree with this to an extent, especially when the lambda involved is very small, but what if it needs to be a multi-line lambda that runs into a lot of indentation issues, or involves a somewhat obfuscated list comprehension or some other device?

My question is: what approaches exist for determining where to draw the line between a useful in-line anonymous function that is "self-contained" enough that it is more effective to write it directly versus an in-line function that is too complex and should be wrapped in a helper function. Are there other considerations I'm not taking into account?

For example: this post on this issue in JavaScript states and affirms many of the concerns I've listed. Is this codified for programming in general? Is it language or paradigm-specific? And what about the other side of the debate?

1 Answers1

2

You draw the line based on length and repetition. A lambda is okay if it's short and not repeated. Once you get into multiple lines, or are repeating it multiple times, you should really give it a name. If your data structure changes, it's no big deal to change one or two short lambdas, especially in a strong statically typed language. For some reason, though, lambdas give people a blind spot to repetition.

JavaScript is really the only language I've seen where multi-line anonymous functions are commonly accepted. I'm not sure what it is about the language that makes it that way. It may be more a cultural thing. That doesn't make it a best practice, however, just a common one. Also, the same rules apply about repetition. More so, since repetition of longer functions is worse.

Karl Bielefeldt
  • 148,830