Re: [Python-ideas] Keyword only argument on function call

On Sat, Sep 08, 2018 at 09:54:59PM +0200, Anders Hovmöller wrote: [...] [Steven (me)]
Enough with the false accusations of straw-manning. I am stating my prediction of the consequence of your proposal. Just because you dislike the conclusion I draw doesn't make it a straw-man, and your repeated false accusations (whether intentional or not) amount to Poisoning The Well. "Steven's arguments are straw-men, so we don't need to address them or pay attention to him." Except it isn't a straw-man. You might disagree, which is your right, you might even just dismiss them as "well that's your opinion" (it *is* my opinion, but I hope a reasoned, logical one), you might even think that the consequences I state are a good thing. But stop trying to poison my reputation by labelling me a straw-manner.
For short argument lists, there's little or nothing wrong with positional arguments. In fact, I would say that positional arguments are, in some circumstances, far better: len(obj) versus len(target=obj) mylist.append(item) versus mylist.append(obj=item) My argument isn't about making absolute judgements of what is good or bad in all cases. It is about weighing up the benefit in some cases (which I have acknowledged) against the disadvantage in other cases. [...]
No. I argued that your proposed syntax could become the perferred idiom because it is short and concise and people mistake that for "great". I'm not blind to the advantage. If I had to make many function calls that looked like this: result = function(spam=spam, eggs=eggs, cheese=cheese, foo=foo, bar=bar, baz=baz, fe=fe, fi=fi, fo=fo, fum=fum) I'd be sick of it too and want something better. But we have to balance many competing and often contradictory interests, and I don't think you have made your case that the pain of the above is worse than the (alleged) benefit of being able to write it in a more terse, implicit way: result = function(*, spam, eggs, cheese, foo, bar, baz, fe, fi, fo, fum) is shorter, but is it really better? I don't think you've made that case. But many people do seem to think shorter is better as a general rule.
Yes, open() is a good example of how long parameter lists are not necessarily a bad thing. With sensible defaults, probably 95% of calls to open need no more than one or two arguments. But can you remember the Bad Old Days before programming languages supported default values? I do. Now imagine making a call to open() with eight required arguments.
In any case I’m proposing a way to mitigate the pain in a subset of cases (probably not the case of open()!).
Yes, I acknowledge that. Just because I sympathise with your pain doesn't mean I want to see your syntax added to the language.
Indeed.
Not at all. As I already stated, keyword arguments are great, and I'm not arguing for hair-shirt programming where we intentionally make things as painful as possible. I'll make an analogy here. Pain, real physical pain, is bad, and it is both kind and medically advantagous to reduce it when necessary. But *necessary* is the key word, because sometimes pain is an important biological signal that says Don't Do That. People with no pain receptors tend to die young because they repeatedly injure themselves and don't even know it. Good doctors make careful judgement about the minimum amount of painkillers needed, and don't hand out morphine for stubbed toes because the consequences will be worse than the benefit gained. The analogy in programming follows: reducing immediate pain can, sometimes, cause long-term pain in the form of technical debt, which is worse. It takes a careful balancing act to decide when it is appropriate to take on technical debt in order to avoid short-term annoyance. We cannot hope to make such a sensible decision if we focus only on the immediate relief and not on the long term consequences.
I don't think the pain is all that great. Its a minor annoyance to write keyword arguments like parameter=parameter, and a good IDE or editor can help there. But I acknowledge there is some pain, and the more you need to do this, the more you feel it. But in any case, you made a proposal. I don't have to come up with a better proposal before I am permitted to argue against yours. "We must do something. This is something, therefore we must do it." is never a valid argument.
I have done nothing but call it a trade off! I've repeatedly argued that in my opinion the benefit (which I have repeatedly acknowledged!) doesn't outweigh the (predicted) costs as I see them. [...]
Sorry for being unclear. I meant that we shouldn't encourage complex, multi-argument functions, while still accepting that sometimes they are unavoidable (and even occasionally a good thing).
I don't dispute the numbers you get from your code base. You should be careful about generalising from your code to other people's, especially if you haven't seen their code.
Pointing out that weakness in your argument is not a straw man.
You did notice that not just me called it a straw man on this list right?
Yes I did. Many people call the world flat too. What's your point? -- Steve

The proposal is to eliminate the redundancy of writing name=name repeatedly. But IMHO it doesn't do that consistently. That is it allows both forms mixed together, e.g., f(*, a, b, c=x, d, e) I believe this is confusing in part because the * need not be near the arguments it affects. Consider open(*, name='temp.txt', mode='r', buffering=-1, encoding='utf-8', errors) By the time you get to the last arg, you'll have forgotten the * at the beginning. If Python were to adopt a syntax to address this, I think it should be something like f(=a, =b, c=x, =d, =e) open(name='temp.txt', mode='r', buffering=-1, encoding='utf-8', =errors) Where an = in an argument list without a name in front of it uses the symbol on the right hand side as the name. --- Bruce

I just realized I have another question for you: If you had to chose which one would you prefer: f(*, a b, c) or: f(=a, =b, =c) ? I know you’re clearly against the entire idea but it seems we should prefer the least disliked alternative in such a scenario.

On Mon, Sep 10, 2018 at 08:05:22AM +0200, Anders Hovmöller wrote:
I just realized I have another question for you:
Is that a generic you or just me personally? :-)
I can't say I particularly like either syntax, but if I had a gun pointed at my head and had to choose one, I'd *probably* prefer something like this: open("myfile.txt", 'r', =buffering, =encoding, =errors, newline='\r', =closefd, opener=get_opener()) over this: open("myfile.txt", 'r', *, buffering, encoding, errors, newline='\r', closefd, opener=get_opener()) In the second case, the * is too easy to miss, leaving us with what looks like a confusing mix of positional and keyword arguments. Hmmm... a thought comes to mind... Suppose we had a wild-card symbol that simply told the parser to use the same string as that on the left hand side of the = sign, that might be promising. For the sake of illustration, I'm going to use the Unicode Snowman symbol, but that's just a place-holder. ☃ copies the token from the left hand side of the = to the right hand side. It is a syntax error if it doesn't follow an = sign. Then we could be (slightly) concise AND explicit: open("myfile.txt", 'r', buffering=☃, encoding=☃, errors=☃, newline='\r', closefd=☃, opener=get_opener()) would expand to: open("myfile.txt", 'r', buffering=buffering, encoding=encoding, errors=errors, newline='\r', closefd=closefd, opener=get_opener()) But honestly, this feels Perlish to me, or something that belongs in a personal pre-processor rather than the language. (Maybe we should embrace the concept of a Python pre-processor?)
I know you’re clearly against the entire idea but it seems we should prefer the least disliked alternative in such a scenario.
I accept this is a pain point for some people and some code bases. I'm not convinced it is painful enough to need a language-wide syntactic solution (but I don't have any better solution except "refactor until the pain goes away"), or that the benefit outweighs the real and potential costs. I wouldn't quite describe it as being "against the entire idea". It's not that I'm against the very idea of improving parameter handling in Python. I just don't think this is the way. -- Steve

The proposal is to eliminate the redundancy of writing name=name repeatedly. But IMHO it doesn't do that consistently. That is it allows both forms mixed together, e.g., f(*, a, b, c=x, d, e) I believe this is confusing in part because the * need not be near the arguments it affects. Consider open(*, name='temp.txt', mode='r', buffering=-1, encoding='utf-8', errors) By the time you get to the last arg, you'll have forgotten the * at the beginning. If Python were to adopt a syntax to address this, I think it should be something like f(=a, =b, c=x, =d, =e) open(name='temp.txt', mode='r', buffering=-1, encoding='utf-8', =errors) Where an = in an argument list without a name in front of it uses the symbol on the right hand side as the name. --- Bruce

I just realized I have another question for you: If you had to chose which one would you prefer: f(*, a b, c) or: f(=a, =b, =c) ? I know you’re clearly against the entire idea but it seems we should prefer the least disliked alternative in such a scenario.

On Mon, Sep 10, 2018 at 08:05:22AM +0200, Anders Hovmöller wrote:
I just realized I have another question for you:
Is that a generic you or just me personally? :-)
I can't say I particularly like either syntax, but if I had a gun pointed at my head and had to choose one, I'd *probably* prefer something like this: open("myfile.txt", 'r', =buffering, =encoding, =errors, newline='\r', =closefd, opener=get_opener()) over this: open("myfile.txt", 'r', *, buffering, encoding, errors, newline='\r', closefd, opener=get_opener()) In the second case, the * is too easy to miss, leaving us with what looks like a confusing mix of positional and keyword arguments. Hmmm... a thought comes to mind... Suppose we had a wild-card symbol that simply told the parser to use the same string as that on the left hand side of the = sign, that might be promising. For the sake of illustration, I'm going to use the Unicode Snowman symbol, but that's just a place-holder. ☃ copies the token from the left hand side of the = to the right hand side. It is a syntax error if it doesn't follow an = sign. Then we could be (slightly) concise AND explicit: open("myfile.txt", 'r', buffering=☃, encoding=☃, errors=☃, newline='\r', closefd=☃, opener=get_opener()) would expand to: open("myfile.txt", 'r', buffering=buffering, encoding=encoding, errors=errors, newline='\r', closefd=closefd, opener=get_opener()) But honestly, this feels Perlish to me, or something that belongs in a personal pre-processor rather than the language. (Maybe we should embrace the concept of a Python pre-processor?)
I know you’re clearly against the entire idea but it seems we should prefer the least disliked alternative in such a scenario.
I accept this is a pain point for some people and some code bases. I'm not convinced it is painful enough to need a language-wide syntactic solution (but I don't have any better solution except "refactor until the pain goes away"), or that the benefit outweighs the real and potential costs. I wouldn't quite describe it as being "against the entire idea". It's not that I'm against the very idea of improving parameter handling in Python. I just don't think this is the way. -- Steve
participants (3)
-
Anders Hovmöller
-
Bruce Leban
-
Steven D'Aprano