3 ms·
Other languages seem to get it right. Even C++! #include <vector> static int foo(std::vector<int> x = {}) { x.push_back(10); return x.size(
by alextgordon 11y ago
Other languages seem to get it right. Even C++!
#include <vector>
static int foo(std::vector<int> x = {}) {
x.push_back(10);
return x.size();
}
int main (int argc, char const *argv[]) {
printf("%d\n", foo()); // 1
printf("%d\n", foo()); // still 1
return 0;
}
def foo(x=[]):
x.append(10)
return len(x)
print(foo()) # 1
print(foo()) # 2? wtf?
- eiopa 11y agoES6 got this right too. This design decision makes me die a little every time I have to do: def foo(x=None): if not x: x = [] ...
- dajonker 11y agoThat will get you into trouble as well, please use: if x is None: x = [] ... etc.
- switch007 11y agoOr even "prettier": x = [] if x is None else x
- knite 11y agoI'm partial to: x = x or []
- acveilleux 11y agoOnly works when x is truthy for all legal x values, excluding x=0.
- deleted 11y ago[deleted]
- blub 11y agoSmall tip: you can shorten your snippet by completely removing main's parameters and the return 0 and still have a valid c++ program.
- alextgordon 11y agoI did pause to think about this, but sod's law dictates that if you remove the parameters to main, you will have to add them back in again. :)
- millstone 11y agoC++ its own insane behavior, where default arguments are determined at the call site instead of at runtime. This means your function can get another function's default arguments. #include <iostream> struct Base { virtual void foo(const char *name = "base") { std::cout << "Base impl with " << name << " param\n"; } }; struct Derived : public Base { virtual void foo(const char *name = "derived") override { std::cout << "Derived impl with " << name << " param\n"; }; }; int main(void) { Base *b = new Derived(); b->foo(); } prints "Derived impl with base param" Fortunately Python avoided that bit of silliness.
- denim_chicken 11y agoThis behavior is pretty reasonable to me.
- nbadg 11y agoI'm not familiar enough with the innards of other languages to make any definitive comments on it, but I will say that the challenge is in combining a high-level language with late-binding closures with memoization. I'm not aware of a strategy for that which is always intuitive for every program you write; I think it's just a language design combination that has a very high probability of developing "gotchas" no matter what you do. Also, on a related note, I really love late binding and memoization, so I'm definitely biased on the side of "I understand why the language designers made this decision, and though the ramifications bother me a little bit, I much prefer this way". On a third note (because hey, why not), with type hints being a thing now, maybe it would be worth considering a default eval hint. It could default to current behavior, and therefore retain backwards compatibility, but you could add syntax to declare defaults as new variables. That might be a smart compromise.