On Fri, Dec 3, 2021 at 3:47 PM Abe Dillon <abedillon@gmail.com> wrote:
This seems like an exceedingly minor complaint. The obvious answer is: you invoke the default behaviour by not passing the argument. And yes, I know that's less explicit, but that's kinda the whole point of defaults to begin with. It's behavior when the user decides not to specify their own. Nobody's asking "what do I pass to logging.config.fileConfig to explicitly invoke the logging module's default behavior?!" The answer is simply: don't configure logging. It's not rocket science.
I'd say it isn't "less explicit". It's actually the ultimate definition of not doing something: you just... don't do it. The same line of explanation is important when working with callback functions: def callback(*a): print("Doing stuff") button.signal_connect("clicked", callback()) Oops, you called the callback instead of passing it to the signal_connect function. What's the solution? DON'T call the callback at this point. How do you NOT call something? Well, how do you call it? You put parentheses after it. So how do you not call it? You don't put the parentheses after it. Python is fairly good at giving you syntactic features that do things, such that you can not do them by omitting them. So I don't think anyone is truly concerned about the pure "don't pass the argument" case. The problem is the "maybe pass the argument" case. That ends up looking like this: c = 42 if cond: func(a, b) else: func(a, b, c) # or args = {} if not cond: args["c"] = 42 func(a, b, **args) # or if you know what the default is: c = some_default if not cond: c = 42 func(a, b, c) The first two will, of course, continue to work. The second one is a fairly clear way to indicate whether or not a parameter should get a value. The problem with the third is that it requires a documented and future-guaranteed default value, published and promised to work, and that simply isn't always possible or practical. So, yes, some forms of default might be a little unclear. And if you're converting an existing codebase, it may be necessary to maintain "if c is None: c = some_default" in the body forever, or until such time as you can remove the support for None as a parameter. But None isn't truly the default value.
"Can we agree that, like salt, sugar, and bike-shedding, sometimes you can have *too much* explicitness in code?"
Surely *you* would never agree that there's such a thing as *too much* bike-shedding! Isn't that your raison d'ĂȘtre?!
I never said one had to be a Nazi about stamping out every use of the sentinel... er... idiom (if you prefer it to hack).
Idiom. Sentinels are extremely important, and PEP 671 isn't proposing to eliminate them. The "hack" part comes when, for technical reasons, a sentinel is used when one isn't logically part of the API. I agree with Steve here: sometimes, the true default is extremely clunky, and it's better to use a sentinel. That's part of why they're never going away (and None will continue to be a popular sentinel). PEP 671 doesn't propose changing every function ever written, because the vast majority of them are perfectly fine as they are.
"The caller's perspective is important. The caller has to read the function signature (either in the documentation, or if they use `help(function)` in the interpreter, or when their IDE offers up tooltips or argument completion). The caller has to actually use the function. We should consider their perspective."
I never said we shouldn't. That's just not what I was talking about at that time and you were misinterpreting my argument.
Yes, absolutely. And that's why the function should be able to put the information in the signature when it's appropriate to, and in the body when it isn't.
Just because it's an idiom, doesn't mean it's actually good. I think the `if __name__ == "__main__":` idiom is a horrible, round-about way of saying "if this file is being run as a script". You might look at that and say "What do you mean? That's exactly what it says!" because you've seen the idiom so many times, just like how you think "x=None" explicitly says "give x the default value", but if you look closely `if __name__ == "__main__":` *doesn't* actually say anything like "if this file is being run as a script", it says a bunch of esoteric and confusing garbage that you've learned to read as "if this file is being run as a script".
TBH I think that the name-is-main idiom isn't too bad, but mainly because I've seen far worse idioms. If someone has a better proposal, I'd be happy to hear it, but the existing idiom isn't horrible. (But you're right. Well-known idioms can indeed be really REALLY bad. Just look at the sorts of things that pre-C99 C code would do.) ChrisA