The multi-line lambda one always makes me want to facepalm. I hear it a lot, but this one is so confused that it’s not even wrong.
First, lambdas in Python can have as many lines as you want. That makes the premise invalid. Seriously. My Hissp project is a Lisp compiler that targets a subset of Python. Its lambdas have the implicit PROGN typical of Lisp, and they compile to Python lambdas just fine. You could wrap your entire Hissp module in a progn and it will compile to a lambda expression that goes on for pages.
So why are people confused about this? I think they’re conflating “lines of code” with “statements”, which are not at all the same thing. It’s true that certain kinds of Python statements typically fit on one line, but none of them have to, and many kinds (block statements, e.g. try-except/try-finally) typically don’t.
So let’s try to steelman this: even multi-line lambdas in Python can’t directly contain statements. (Or, from a certain point of view, they contain only one: an implicit return. But they can call exec() on a string that does, or call other things that do.)
Second, true functional languages don’t have statements to begin with, only expressions. (Or, from a certain point of view, they only have “expression statements”.) Statements are a holdover from assembly, when the original Fortran mixed math expressions with machine code instructions (the “statements”).
When programming in the functional style, which is when you want lambdas, you don’t use statements anyway. Expressions are all you need! You don’t even need a progn unless you have side effects, which is also not functional style.
So then the argument becomes “Python would not need decorators if anonymous functions could have statements.”
Now what does the “need” part mean? Decorators are just syntactic sugar. You can get exactly the same behavior without them, so what use are decorators at all? Let’s look at what the sugar does:
“Need” might be overstated. But why is the decorator better? The main reason is that it eliminates the duplication of <name>, which appears three times in the desugared version. It’s also shorter and allows you to write the decorator expression before the function. Do lambdas have <name>s? No.
So what are they suggesting we could do instead? It’s probably
which does already work in Python if <body> doesn’t have statements (and it wouldn’t in the functional style). But we’re still missing the function’s docstring, and its __name__ attribute will be '(lambda)' instead of <name>. Hypothetically, to fix these, it then becomes something like,
This doesn’t work because def isn’t an expression in Python. It’s not about lambdas anymore.
Now the steelman argument has become “Python would not want decorators if function definitions were expressions.”
But we can see that the decorator version is still better. It doesn’t duplicate the <name>. It doesn’t need another layer of indentation, which gets even worse when nesting these. Can we fix this? Maybe?
def defn(*decorators):
def _(name, f):
while decorators:
f = decorators.pop()(f)
globals()[name] = f
f.__name__ = name # etc.
return _
defn(<decorator expression>)(
"<name>", lambda <args>:
<body>
)
This only assigns to the top level because it uses globals, even if it’s nested in a class or function. Perhaps if we had some kind of preprocessor macro that expanded to an assignment? But now we’ve just re-implemented decorators.
Re #2.
The multi-line lambda one always makes me want to facepalm. I hear it a lot, but this one is so confused that it’s not even wrong.
First, lambdas in Python can have as many lines as you want. That makes the premise invalid. Seriously. My Hissp project is a Lisp compiler that targets a subset of Python. Its lambdas have the implicit PROGN typical of Lisp, and they compile to Python lambdas just fine. You could wrap your entire Hissp module in a
progn
and it will compile to a lambda expression that goes on for pages.So why are people confused about this? I think they’re conflating “lines of code” with “statements”, which are not at all the same thing. It’s true that certain kinds of Python statements typically fit on one line, but none of them have to, and many kinds (block statements, e.g. try-except/try-finally) typically don’t.
So let’s try to steelman this: even multi-line lambdas in Python can’t directly contain statements. (Or, from a certain point of view, they contain only one: an implicit
return
. But they can call exec() on a string that does, or call other things that do.)Second, true functional languages don’t have statements to begin with, only expressions. (Or, from a certain point of view, they only have “expression statements”.) Statements are a holdover from assembly, when the original Fortran mixed math expressions with machine code instructions (the “statements”).
When programming in the functional style, which is when you want lambdas, you don’t use statements anyway. Expressions are all you need! You don’t even need a progn unless you have side effects, which is also not functional style.
So then the argument becomes “Python would not need decorators if anonymous functions could have statements.”
Now what does the “need” part mean? Decorators are just syntactic sugar. You can get exactly the same behavior without them, so what use are decorators at all? Let’s look at what the sugar does:
becomes
“Need” might be overstated. But why is the decorator better? The main reason is that it eliminates the duplication of <name>, which appears three times in the desugared version. It’s also shorter and allows you to write the decorator expression before the function. Do lambdas have <name>s? No.
So what are they suggesting we could do instead? It’s probably
which does already work in Python if <body> doesn’t have statements (and it wouldn’t in the functional style). But we’re still missing the function’s docstring, and its
__name__
attribute will be'(lambda)'
instead of <name>. Hypothetically, to fix these, it then becomes something like,This doesn’t work because
def
isn’t an expression in Python. It’s not about lambdas anymore.Now the steelman argument has become “Python would not want decorators if function definitions were expressions.”
But we can see that the decorator version is still better. It doesn’t duplicate the <name>. It doesn’t need another layer of indentation, which gets even worse when nesting these. Can we fix this? Maybe?
This only assigns to the top level because it uses globals, even if it’s nested in a class or function. Perhaps if we had some kind of preprocessor macro that expanded to an assignment? But now we’ve just re-implemented decorators.