I really think you’re underestimating people’s ability to figure things out. Remember, almost nothing is truly intuitive - everything has to be learned. One thing is not easier to learn than another simply because you personally already know it.
Remember that, prior to Python 3.8, an f-string couldn’t do this: f"{1+2=}" But now it can. And people love that feature. It’s exactly the same problem as you’re complaining of: the equals sign has nothing to the right of it. It works because it makes good sense, as soon as it has been learned, and therefore can be easily remembered: if there’s nothing after the equals sign, it’s exactly what came before it.
I think people use “confusing” in different ways in this discussion. The construct is confusing for people unfamiliar with it (it looks like an assignment or a keyword paramete, but nothing’s getting assigned or passed), but that’s a learning question, and anything can be learned reasonably quickly. But there’s also the confusion that comes from the construct looking unexpected, or incongruous, in code that you’re trying to read. This confusion comes from a feeling that the construct somehow doesn’t “fit” with other parts of the language, and is very hard to define precisely, but it doesn’t go away nearly as quickly as the first sort, and can remain as an ongoing “papercut” type of annoyance when trying to read other people’s code.
Personally I think this syntax is confusing in both senses. I’m OK with the idea that I’ll get over the first form of confusion, but I’m much less confident that I’ll get over the second form - this construct just doesn’t seem to flow naturally in the examples I’ve seen, and I don’t think that feeling will go away easily.
(And yes, I’m aware this is subjective - so the decision will probably come down to “does this feature do more harm than good, in terms of the number of people who will love or hate it?”)
That’s very fair. I’m curious whether you use the very-similar construct in f-strings, and whether that also has that “papercut” annoyance. If you do, what makes the difference? (Like, is it because the f-string feature “feels like” a debugging feature?) If you don’t, is there a reason for that, and do you feel that the feature was a bad one? (Or, again, that it’s “only a debugging feature” and that makes a difference to perception?) Not judging in any way based on the answers, just looking for opinions.
And this is not just to Paul - to anyone else who dislikes this proposal, what are your views on this?
I used to think the dangling = in f-strings was really weird, but now I don’t anymore. I think a major difference between dangling = in f-strings and this proposal is that f-strings (before PEP 701/Syntactic formalization of f-strings at least but I don’t things have changed since) are already special. They already come with special rules which means the identifier inside the f-string placeholder is not treated like a normal python identifier. Adding = to that is weird at first but makes sense once you realize it’s just about formatting and doesn’t change the meaning of the thing before.
In contrast, omitting the trailing = in the proposed syntax (assuming it goes with the trailing =) would potentially cause an object to be used as the wrong argument, which in the best case just crashes your program or is caught by tooling, but in the worst case causes some weird runtime bug that is (potentially) hard to track down.
I don’t use it much, but mainly because I routinely forget the syntax. It’s slightly different, because as it’s mainly a debugging tool, I don’t see it in other people’s code (which makes it less easy to get used to, but also less likely that it’ll annoy me in terms of comprehension like I described above).
I feel that the f-string construct is OK, mostly because it is a debugging tool and therefore concerns about reading it in other people’s code are not as significant. Whereas with this proposal, there’s a strong likelihood that I’ll encounter other people’s code which uses it.
I would be uncomfortable if people started using the trailing = syntax in f-strings in production code.
Regarding debug f-strings, I forget that it exists most of the time but when I do use it, I generally like it and it reads fine.
I think it’s because we’ve already learned that string formatting is it’s own micro-language.
I don’t like the proposal, and I don’t like the syntax in f-strings either. It’s mostly just my subjective opinion though - it looks like an incomplete expression to me.
For keyword arguments I suspect this would hide a lot of subtle bugs when things get bound implicitly in a way you don’t expect. I also feel this would be difficult to teach the rules for.
I do sympathize with the name=name problem, but at least it’s explicit and consistent.
I like this idea. I use keyword arguments (and even keyword only arguments) fairly heavily, and would make use of this if it were made available. I find (for myself, at least) using keyword arguments makes code easier to follow and mistakes harder to make. I do see a lot of f(x=x, y=y, z=z), and I do feel a shorter form would be an improvement. The suggested f(a, *, b, c, d) reads the best for me, though I don’t disagree with the objections listed in the PEP.
There’s a common pattern in javascript/typescript to achieve this using the shorthand object notation (f(a, { b, c, d })). There is an eslint rule to enforce it’s usage, which we may be able to use as a proxy for “do people like this language feature”. An extremely rough search of github usage (search hits for /object-shorthand.+%s/) looks like:
Enabled (always, properties, consistent-as-needed) is ~76%, disabled (never) is ~5%, and unclear/neutral (methods, consistent) making up the remaining ~18%. Though, this is for any use of the shorthand (not necessarily for building an object to be used as a function argument), and doesn’t give us any insight into why they have it enabled.
Personally, though, when I enable it I do so for readability, and would enable a similar lint for my python code if the feature was available.
This is not an issue with named arguments; the argument is passed explicitly, not implicitly. Implicitly passing arguments would mean that any existing variable in the calling context or parent scopes with the right name is considered a correct argument. However, this is not true.
I think one could argue that the popularity of ECMAScript’s object literal shorthand is largely because its function declaration and invocation syntaxes are not as flexible as Python’s. Using object unpacking in function declarations - and similarly, object literal shorthand - became prevalent because JS doesn’t have keyword arguments or argument default values (my mistake, it has defaults, but they’re order sensitive). And that becomes very irritating with, say, React component props.
Again this is just my opinion, but I don’t find the JS object shorthand a compelling reason for adding something similar to Python, which already has (imo) very flexible function calls.
I go looking for this every 6 months or so I’m glad I found a thread this time. It seems an obvious improvement to me and I’m shocked we got := first.
In the work codebase there are 2,114 examples across 166,374 lines.
But more importantly if this were available I would start a broad push to increase the use of * to force arguments to be keyword only. I expect that would significantly increase the number of instances. But it’s a harder thing to search for.
I did something similar in my personal JS projects after I learnt about it’s {...{ x, y }} construct.
I also favor the x= syntax, the idea that if the right hand side is missing then it’s the same as the left seems quite straight forward.
I find the * based syntax very not obvious.
The ... style seems unnecessarily verbose.
And the authors =x looks weird and kinda invites =a+b
To be fair, right now it’s a syntax error, which is easy to locate and fix (and an IDE will flag it). If this idea was implemented then it could silently work for a while, and the IDE won’t say anything.
I’m fine with the x= syntax because I got used to it in f strings. But what about some special sentinel symbol to indicate the argument should be populated with the variable with the same name as the parameter:
I don’t like this, I would prefer the bare x= syntax, but maybe an example like this should appear in the pep as a rejected idea?
I actually like the semantics of the x=" because a similar construction is used in handwriting. But it’s just too close visually and typo-distance to the empty string "".
I would also suspect that, if it became something syntactically valid, the rate of people accidentally typing it would naturally increase, as the idea would be planted.
(I deleted and tried to repost this, because I had inadvertently made it a reply to someone else, which it shouldn’t have been. But now it’s being rejected because the body is too similar to what I posted already. Hopefully this preamble makes it different enough.)
In my opinion, if we’re going with anything other than identifier= (which is by far my preference, since not only is it the same syntax as in f-strings, but it is precisely the same expansion), then we should choose something more distinct from it than =identifier.
How about ^identifier? It looks like a little up-arrow pointing to a variable that was assigned above. Like =, it’s a binary operator, so it’s a syntax error currently.