def a(n):
def b():
print(n)
return b def a(n):
return lambda: print(n)It is annoying that you have to give the function a name, though.
def b(x):
return x + 1
vs x => x + 1This is a code smell for sure.
You are basically saying that one should never need a multi-line lambda. Obviously, I disagree.
I will mention a core aspect of my argument, to add to your point.
When you make a named function and then use it separately somewhere else, there is a loss of locality. The logic is now further from its point of use. This is a cost, and sometimes it is an unreasonable one.
It's a very intentional language limitation, much as semantic whitespace is an intentional limitation.
And there is actually a language difference. A for loop is a statement. A lambda is an expression. Python doesn't let you put statements into expressions.
I've sometimes wondered whether code would be universally clearer if all you could do in a loop is have a one-liner or call another function/method (mainly when looking at my own code within loops and thinking WTF!!!).
Would probably cause issues when teaching programming though. It would be interesting to have a compiler switch that enforced this...
foreach ( $item in $list )
{
if ( 1 == some_function( $item ) )
{
continue;
}
else
if ( 2 == some_function( $item ) )
{
break;
}
else
{
another_function( $item );
}
}
But I would immediately concede that it is starting to miss the entire point of why it was enforced in the first place...Streams and repeated application of short anonymous functions are a much better solution to the method chaining issue.
If js supported better streaming tools, they'd be less common in js too.
I've written snippets or data structures one way or another as I'm sure many have, and in my experience the results have been mixed. This and the fact that reduce has no bearing on your app architecture, I do see this as arguing over a small and vague gain or loss.
I’m having a difficult time understanding what you mean here. Can you offer an example?
I have never felt compelled to write a multi line lambda.
fooBaz(x => {
// multiple lines of logic
})
In python, you are forced to move the logic away from the point of usage, which means you lose some locality. This loss is sometimes not worth getting a "name" for the logic.Of course, sometimes it is better to create a named function away from the point of usage, but I don't think that is always the case.
You end up seeing functions declared within functions so that people can work around this limitation and it is grotesque.
There are a lot of cases like GUI programming where you need a lot of handlers which are suitable for lambda because they don't have a good name, and should never be called manually, and often they have multi-lines of codes.
In typescript, if I have a bunch of "User" objects where each user has an "name" and "age" field, and I want to print a comma separated list of all those names formatted as "name -- age", it's simple. I write:
let userNamesList = let userNames = users.map(u => `${u.name} -- ${u.age}`).join(", ")
console.log(userNamesList).
This is possible in no small part because map is generic.In go, to get the same level of expressiveness, I'd have to write the following stuff around it:
func mapUsersToStrings(f func(u User) string, users []User) []string {
result := make([]string, len(users))
for i := 0; i < len(users); i++ {
result = append(result, f(users[i]))
}
}
And after writing that boilerplate, I can finally write: userNamesList := strings.Join(mapUsersToStrings(func(u User) string { return fmt.Sprintf("%s -- %d", u.name, u.age) }), ", ")
That boilerplate, of having to write a specialized map/filter/etc function with a for loop for every combination of types you transform between (mapUsersToStrings, mapUsersToAddresses, mapUsersToAges) is really annoying.It's harder to point to many other cases because, simply enough, people don't write such cases. The fact of the matter is just that go libraries make very sparing use of first-class functions because the lack of generics prevents it from working well, and so we end up with an entire language ecosystem where code is harder to read and with fewer simple abstractions reused across it.
You can still write any code without good generics or first-class functions, you'll just have more programmers writing more code with less clean abstractions.