
On 2021-10-30 16:12, Chris Angelico wrote:
Increasingly it seems to me as if you are placing inordinate weight on the idea that the benefit of default arguments is providing a "human readable" description in the default help() and so on. And, to be frank, I just don't care about that. We can already provide human-readable descriptions in documentation and we should do that instead of trying to create gimped human-readable descriptions that only work in special cases. Or, to put it even more bluntly, from my perspective, having help() show something maybe sort of useful just in the case where the person wrote very simple default-argument logic and didn't take the time to write a real docstring is simply not a worthwhile goal.
Interesting. Then why have default arguments at all? What's the point of saying "if omitted, the default is zero" in a machine-readable way? After all, you could just have it in the docstring. And there are plenty of languages where that's the case.
The point of default arguments is to allow users of the function to omit arguments at the call site. It doesn't have anything to do with docstrings. Or do you mean why not just have all omitted arguments set to some kind of "undefined" value and then check each one in the body of the function and replace it with a default if you want to? Well, for one thing it makes for cleaner error handling, since Python can tell at the time of the call that a required argument wasn't supplied and raise that error right away. It's sort of like a halfway type check, where you're not actually checking that the correct types of arguments were passed, but at least you know that the arguments that need to be passed were passed and not left out entirely. For another thing, it does mean that if you know the default at the time you're defining the function, you can specify it then. What you can't do is specify the default if you don't know the default at function definition time, but only know "how you're going to decide what value to use" (which is a process, not a value).
I'm of the opinion that having more information machine-readable is always better. Are you saying that it isn't? Or alternatively, that it's only useful when it fits in a strict subset of constant values (values that don't depend on anything else, and can be calculated at function definition time)?
Now wait a minute, before you said the goal was for it to be human readable, but now you're saying it's about being machine readable! :-) What I am saying is that there is a qualitative difference between "I know now (at function definition time) what value to use for this argument if it's missing" and "I know now (at function definition time) *what I will do* if this argument is missing". Specifying "what you will do" is naturally what you do inside the function. It's a process to be done later, it's logic, it's code. It is not the same as finalizing an actual VALUE at function definition time. So yes, there is a qualitative difference between: # this if argument is undefined: argument = some_constant_value # and this if argument is undefined: # arbitrary code here I mean, the difference is that in one case arbitrary code is allowed! That's a big difference. Based on some of your other posts, I'm guessing that what you mean about machine readability is that you appreciate certain kinds of labor-saving "self-documentation" techniques, whereby when we write the machine-readable code, the interpreter automatically derives some human-readable descriptions for stuff. For instance when we write `def foo` we're just defining an arbitrary symbol to be used elsewhere in the code, but if we get an exception Python doesn't just tell us "exception in function number 1234" or the line number, but also tells us the function name. And yeah, I agree that can be useful. And I agree that it would be "nice" if we could write "len(a)" without quotes as machine-readable code, and then have that stored as some human-readable thing that could be shown when appropriate. But if that's nice, why is it only nice in function arguments? Why is it only nice to be able to associate the code `len(a)` with the human-readable string "len(a)" just when that string happens to occur in a function signature? On top of that, even if I agree that that is useful, I see the benefit of that in this case (generating docstrings based on default arguments) as very marginal. I think I agree with the spirit of what you mean "having more information machine-readable is always good", but of course I don't agree that that's literally true --- because you have to balance that good against other goods. In this case, perhaps most notably, we have to balance it against the cognitive load of having two different ways to write arguments, which will have quite different semantics, which based on current proposals are going to differ in a single character, and both of which can be interleaved arbitrarily in the function signature. That's leaving aside all the other questions about the more subtle details of the proposal (like mutual references between defaults), which will only increase the potential cognitive burden for code readers. So yes, it's true that adding convenience functions to derive human-readable forms from machine-readable code is handy, but it's not ALWAYS automatically good regardless of other considerations, and I don't see that it outweighs the costs here. The benefit of autogenerating the string "len(a)" from the argument spec isn't quite zero but it's pretty tiny. -- Brendan Barnwell "Do not follow where the path may lead. Go, instead, where there is no path, and leave a trail." --author unknown