On Sun, Dec 5, 2021 at 3:39 PM David Mertz, Ph.D. <david.me...@gmail.com> wrote: > > On Sat, Dec 4, 2021 at 11:25 PM Chris Angelico <ros...@gmail.com> wrote: >> >> > def add(a, b): >> > return a+b >> > How could you write that differently with your PEP >> >> I wouldn't. There are no default arguments, and nothing needs to be changed. > > > I do recognize that I *could* call that with named arguments. I also > recognize that the long post I wrote in the bath from my tablet is rife with > embarrassing typos :-). > > Technically, I'd need `def add(a, b, /)` to be positional-only. But in > practice, almost everyone who writes or calls a function like that passes by > position. I'm not sure that I've *ever* actually used the explicit > positional-only `/` other than to try it out. If I have, it was rare enough > that I had to look it up then, as I did just now. >
No problem. Doesn't really matter. In any case, argument defaults have always been orthogonal with parameter passing styles (named or positional), and that's not changing. >> Actually PEP 671 applies identically to arguments passed by name or >> position, and identically to keyword-only, positional-or-keyword, and >> positional-only parameters. >> >> >>> def f(a=>[], /, b=>{}, *, c=>len(a)+len(b)): >> ... print(a, b, c) > > > Wow! That's an even bigger teaching nightmare than I envisioned in my prior > post. Nine (3x3) different kinds of parameters is already too big of a > cognitive burden. Doubling that to 18 kinds makes me shudder. I admit I sort > of blocked out the positional-only defaults thing. > > I understand that it's needed to emulate some of the builtin or standard > library functions, but I would avoid allowing that in code review... > specifically because of the burden on future readers of the code. > What you're missing here is that it's not 3x3 becoming 3x3x2. Everything is completely orthogonal. For instance, we don't consider string arguments to be a fundamentally different thing from integer arguments: def f(text, times): ... f("spam", 5) They're just... arguments! And it's not massively more cognitive load to be able to pass string arguments by name or position AND to be able to pass integer arguments by name or position. f(text="spam", times=5) f("spam", times=5) That's not a problem, because the matrix is absolutely complete: there is no way in which these interact whatsoever. It's the same with positional and named parameters: the way the language assigns argument values to parameters is independent of the types of those objects, whether they have early-bound defaults, whether they have late-bound defaults, whether they have annotations, and whether the function returns "Hello world". It's not quadratic cognitive load to comprehend this. It is linear. The only thing you need to understand is the one thing you're looking at right now. With function defaults, it is currently the case that any parameter can have a default, so long as there are no positional parameters to its right which lack defaults. That's the only restriction on default arguments. And that restriction is not changing at all by my proposal: it is neither weakened nor strengthened by the fact that the default might be an expression rather than a precomputed value. (By the way, if I ever get the words "argument" and "parameter" wrong, my apologies; but truth be told, everyone does that. The Python grammar specifies that a def statement has a block of params, which is of type arguments_ty. So that's a thing.) CPython currently states that a function's parameters consist of three groups (or five, kinda): def func(pos_only, /, pos_or_kwd, *, kwd_only): ... def func(pos_only, /, pos_or_kwd, *args, kwd_only, **kwargs): ... Inside each group (not counting the collectors *args and **kwargs if present), legality is defined by... well, I'll just quote the grammar file: # There are three styles: # - No default # - With default # - Maybe with default # # There are two alternative forms of each, to deal with type comments: # - Ends in a comma followed by an optional type comment # - No comma, optional type comment, must be followed by close paren # The latter form is for a final parameter without trailing comma. And if you've never thought about type comments, don't worry, neither had I till I was tinkering with the grammar, and we can for the most part ignore them. :) Either the parameter has a default, or it doesn't. A "maybe with default" either looks like a "with default" or a "no default" (and grammatically, it's there to handle that one restriction of "def f(a=1, b):" being invalid, but everything else is fine). I'm not changing any of that. All I'm changing is the default itself: default[default_ty]: | '=' a=expression { _PyPegen_arg_default(p, a, DfltValue) } | '=' '>' a=expression { _PyPegen_arg_default(p, a, DfltExpr) } When a parameter has a default, two options: either it's a default value, or it's a default expression. This change doesn't care what group of parameters it's in - and in fact, it cannot - because any parameter can have, or not have, a default. This is the correct way to add features. Cognitive load goes up linearly, but expressiveness goes up polynomially. Yes, it's possible to write all the different kinds of functions. That's great, that's power! But you don't need to think about every possibility all at once, in a massive N-dimensional matrix. ChrisA _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/SOTFNE3PWSSMYCS52V32E4WNKRO4HAKZ/ Code of Conduct: http://python.org/psf/codeofconduct/