[Python-ideas] Keyword only argument on function call

Steven D'Aprano steve at pearwood.info
Sun Sep 9 01:14:19 EDT 2018


On Sat, Sep 08, 2018 at 09:54:59PM +0200, Anders Hovmöller wrote:

[...]

[Steven (me)]
> > If we believe that this consistency is desirable then maybe this would 
> > be a good thing. Linters could warn when you use "name=spam" instead of 
> > "*, name"; style guides can demand that code always uses this idiom 
> > whenever practical, tutorials and blog posts will encourage it, and the 
> > peer pressure to rename variables to match the called function's 
> > parameters would be a good thing too.
> 
> That’s the same straw man argument as before as far as I can tell.
[...]

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.



> > But if consistency for consistency's sake is not generally a good thing, 
> > then we ought not to add such syntax just for conciseness.
> 
> But conciseness for conciseness sake is just as not-good and we do 
> have special syntax for that: positional arguments. I’m proposing to 
> level the playing field.

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.


[...]
> > Of course I understand that with this proposal, there's nothing 
> > *forcing* people to use it. But it shifts the *preferred* idiom from 
> > explicit "name=spam" to implicit "*, name" and puts the onus on people 
> > to justify why they aren't naming their local variables the same as the 
> > function parameter, instead of treating "the same name" as just another 
> > name.
> 
> Did you just argue that my proposed syntax is so great it’s going to 
> become the preferred idiom? :)

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.


> > but that active preference for long parameter lists seems to be a very 
> > rare, more common is the view that *at best* long parameter lists is a 
> > necessary evil that needs mitigation.
> 
> I think that’s overly doom and gloomy. Just look at all the arguments 
> for open().

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.


> > certainly wouldn't want to put a hard limit on the number of 
> > parameters allowed. But in general, I think it is unquestionable that 
> > long parameter lists are a code-smell.
> 
> Or a domain smell. Some domains are smelly. 

Indeed.


> > It is also relevant in this sense. Large, complex function calls are 
> > undoubtably painful. We have mitigated that pain somewhat by various 
> > means, probably the best of which are named keyword arguments, and 
> > sensible default values. The unintended consequence of this is that it 
> > has reduced the pressure on developers to redesign their code to avoid 
> > long function signatures, leading to more technical debt in the long 
> > run.
> 
> So... you’re arguing Python would have been better off without keyword 
> arguments and default values?

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.


> > Your suggestion would also reduce the pain of functions that require 
> > many arguments. That is certainly good news if the long argument list is 
> > *truly necessary* but it does nothing to reduce the amount of complexity 
> > or technical debt.
> > The unintended consequence is likewise that it 
> > reduces the pressure on developers to avoid designing such functions in 
> > the first place.
> > 
> > This might sound like I am a proponent of hair-shirt programming where 
> > everything is made as painful as possible so as to force people to 
> > program the One True Way. That's not my intention at all. I love my 
> > syntactic sugar as much as the next guy. But I'd rather deal with the 
> > trap of technical debt and excessive complexity by avoiding it in the 
> > first place, not by making it easier to fall into.
> 
> But you’ve only proposed or implied ways to avoid it by force and 
> pain.

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.


> And you’re arguing my suggestion is bad because it lowers pain. 
> So I think you’re contradicting yourself here. That’s fine but you 
> should admit it and call it a trade off at least.

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.


[...]
> >> There are actual APIs that have lots of arguments. GUI toolkits are a great 
> >> example. Another great example is to send a context dict to a template 
> >> engine.
> > 
> > Indeed. And I'm sympathetic that some tasks are inherently complex and 
> > require many arguments. Its a matter of finding a balance between being 
> > able to use them, without encouraging them.
> 
> What does that mean? We shouldn’t encourage GUI toolkits for Python? 
> Or we shouldn’t encourage working with complex domains? You probably 
> meant to say something else but it came across weirdly.

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).


> > You claimed the benefit of "conciseness", but that doesn't actually 
> > exist unless your arguments are already local variables named the same 
> > as the parameters of the function you are calling.
> 
> Which they often already are. Again: I have numbers. You do not. 

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


More information about the Python-ideas mailing list