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?
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.