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?

  • one may argue that conceptually, this has been addressed in How would you know if you've written readable and easily maintainable code? If your peers keep complaining about your way of doing things, be it one way or another, you better change to make them feel better – gnat Dec 15 '14 at 15:08
  • I worry about that in the case when there is a project leader who has extremely strong feelings about one of the approaches, meanwhile the rest of the team has strong opinions about the opposite approach. Knowing if there was a systematic way to appraise "readability" or "encapsulation" in these cases would be a good way to dissolve opinion-based debates about it. – ely Dec 15 '14 at 15:09
  • discussing concerns like this wouldn't be quite welcome over here, see eg How do I explain ${something} to ${someone}? – gnat Dec 15 '14 at 15:16
  • That's why I'm only asking here about the empirical question of whether such practices exist, have been written about before, and can be pointed to neutrally without trying to claim they are right or wrong. I leave the actual human to human explaining out of it since that is not important here. – ely Dec 15 '14 at 15:17
  • what if my_data_structure changes? What if the attribute to sort by becomes bar in a later code refactoring? The data structure changing shouldn't stop you from sorting it. If the data structure's elements change that's a breaking API change that breaks other parts of the code too, so you have more to worry about than just updating the lambda. – Doval Dec 15 '14 at 15:51
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.

  • JavaScript is by far not the only language. Most language with good support for functional programming are used in that way. Scala is a good example. The problems mentioned by the OP do not even occur here, because it has functions and is statically typed so the compiler will complain immediatly if the data structures api changes. – valenterry Dec 15 '14 at 20:22
  • Actually, @valenterry the actual use case in my team's project is a series of poorly written multi-line anonymous functions in an in-house LiveScript-like functional language that is in some ways very similar to scala (and it has static typing). Even in Haskell you can get really bad multi-line lambdas and though the compiler can easily deal with their type signature, humans reading the code sometimes have no hope. – ely Dec 15 '14 at 23:12
  • Well, sure. Anonymous functions are used because we are too lazy to write an own stragety-pattern-like class for each single anonymous function. But if there are more of them or the same one is used multiple times, one should write it once and use it when needed. I would say even two times writing the same anonymous function already shows that it need to be refactored. The approach to decide is always "what cost less in the long term and when does it have to be finished". Unless its extreme time pressure, refactor instead of doing copy&paste even once. That is how I do it. – valenterry Dec 15 '14 at 23:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.