With this being said, I'd encourage everyone to take a bit of a step back: what exactly are people looking for in PEP 572?
I see two main goals:
Most other use cases would significantly hurt readability and seem pretty rare.
Now let's break down the top one:
So there are roughly three main goals here overall. Now, are there better ways to solve these?
(FWIW C solved the while condition one with the C-style for loop, but I'm pretty sure few people here would really go for that.)
C++ has recently solved the if condition by allowing declarations inside the conditions:
if (auto a = 123; a != 456) {
Many languages have a 'let' expression (using Felix as my example):
if let a = 1, b = 2 in a == b then
Swift has taken a bit of a hybrid between the above two:
if let a = 1, b = 2, a == b {
Now, what's the common theme here? Declarations should be separate from expressions. We've got languages that range from baggage-filled to functional to a bit of all of the above, and none of them have added assignment inside an expression.
The argument is roughly the same across all boards: you're putting major but easy-to-miss side effects in the midst of expressions that seem pure.
All this is to say: I'd really encourage everyone here to think a bit more about why exactly you want this feature, and then think if there's really no better way. Any solution that separates declarations would be far more readable, (arguably) more Pythonic, and play more nicely with the new-ish typing features to boot
I understand reluctance to add a syntax exception like this, but I really feel it'd be worth it.
As a side note, I was a strong supporter of comprehension generalizations, f-strings, and dataclasses. However, this proposal seems a bit ugly and excessive for what it's trying to accomplish.
P.S. Yes, the unmatched curly braces were intentional to drive you crazy for a few hours. I blame Randall Monroe. You're welcome.
-- Ryan (ライアン) Yoko Shimomura, ryo (supercell/EGOIST), Hiroyuki Sawano >> everyone else https://refi64.com/
On Wed, Apr 25, 2018 at 09:36:31PM -0500, Ryan Gonzalez wrote:
I have to say I'm not overly thrilled with PEP 572...it's almost odd, because if you asked me back when I first joined this list when I was 13, I would've no doubt said YES.
I have the opposite experience: I've warmed to it the more I have read it. Before Chris had even written this PEP, there was a Python-Ideas thread asking for dedicated syntax in comprehensions alone that would have been equivalent to a binding-expression. I was rather negative about the whole thing (but no where near as negative as I've been in the past when this has come up before), until Chris pointed out that such binding-expressions have value outside of comprehensions.
[...]
Now, what's the common theme here? Declarations should be separate from expressions.
Declarations and assignments are not the same thing.
We've got languages that range from baggage-filled to functional to a bit of all of the above, and none of them have added assignment inside an expression.
And your claim about assignment inside expressions is only true if you ignore the languages where assignment is an expression with a return value. You know, strange and exotic languages with hardly any users or influence, like C, C++, C#, Java, Javascript, Ruby, Perl, PHP, Lisp ...
-- Steve
On April 25, 2018 11:05:04 PM Steven D'Aprano steve@pearwood.info wrote:
On Wed, Apr 25, 2018 at 09:36:31PM -0500, Ryan Gonzalez wrote:
<opinion>I have to say I'm not overly thrilled with PEP 572...it's almost odd, because if you asked me back when I first joined this list when I was 13, I would've no doubt said YES.
I have the opposite experience: I've warmed to it the more I have read it. Before Chris had even written this PEP, there was a Python-Ideas thread asking for dedicated syntax in comprehensions alone that would have been equivalent to a binding-expression. I was rather negative about the whole thing (but no where near as negative as I've been in the past when this has come up before), until Chris pointed out that such binding-expressions have value outside of comprehensions.
[...] Now, what's the common theme here? Declarations should be separate from expressions.
Declarations and assignments are not the same thing.
Yeah, this is what happens when I write these things when tired... I meant to also mention assignments here, and anywhere else I may have used "declaration".
We've got languages that range from baggage-filled to functional to a bit of all of the above, and none of them have added assignment inside an expression.
And your claim about assignment inside expressions is only true if you ignore the languages where assignment is an expression with a return value. You know, strange and exotic languages with hardly any users or influence, like C, C++, C#, Java, Javascript, Ruby, Perl, PHP, Lisp ...
In the majority of these, however, mixing assignments into expressions is considered bad practice.
For instance:
Some of the other languages (e.g. Perl) aren't some I'd regard as positive influences...
-- Steve
Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/rymg19%40gmail.com
-- Ryan (ライアン) Yoko Shimomura, ryo (supercell/EGOIST), Hiroyuki Sawano >> everyone else https://refi64.com/
Steven D'Aprano writes:
On Wed, Apr 25, 2018 at 09:36:31PM -0500, Ryan Gonzalez wrote:
Now, what's the common theme here? Declarations should be separate from expressions.
Declarations and assignments are not the same thing.
Ryan mostly meant "initialization" rather than "declaration", I suspect. In C's for() statement, the first clause in parentheses is initialization, the third is assignment.
FWIW, I had been thinking the same thing (that what is really wanted is initialization clauses in loop statements) but had no concrete suggestions. Now I too have warmed to the binding expression approach (partly because Guido has, so I'm preparing for the inevitable :^), mostly because of Tim's "humorous observation" about use in printf debugging. The fact that there is this use case independent of block variable initialization (ie, in a loop or if statement) is quite attractive to me.
It's true, as I think Antoine pointed out, that it's easy enough to define a wrapper function that prints a value and returns it. But that's not as flexible, and if you have more than one variable to "watch", you either need an argument to the wrapper to provide the variable's name, or different functions for different variables.
On Thu, 26 Apr 2018 20:35:20 +0900 "Stephen J. Turnbull" turnbull.stephen.fw@u.tsukuba.ac.jp wrote:
Steven D'Aprano writes:
On Wed, Apr 25, 2018 at 09:36:31PM -0500, Ryan Gonzalez wrote:
Now, what's the common theme here? Declarations should be separate from expressions.
Declarations and assignments are not the same thing.
Ryan mostly meant "initialization" rather than "declaration", I suspect. In C's for() statement, the first clause in parentheses is initialization, the third is assignment.
FWIW, I had been thinking the same thing (that what is really wanted is initialization clauses in loop statements) but had no concrete suggestions. Now I too have warmed to the binding expression approach (partly because Guido has, so I'm preparing for the inevitable :^), mostly because of Tim's "humorous observation" about use in printf debugging. The fact that there is this use case independent of block variable initialization (ie, in a loop or if statement) is quite attractive to me.
It's true, as I think Antoine pointed out, that it's easy enough to define a wrapper function that prints a value and returns it.
That wasn't me, but I agree with the idea anyway :-)
Regards
Antoine.
[Ryan Gonzalez rymg19@gmail.com]
I have to say I'm not overly thrilled with PEP 572...it's almost odd, because if you asked me back when I first joined this list when I was 13, I would've no doubt said YES. But, since then, I've gone across many projects and languages, and fundamentally I have never felt hurt by the lack of assignment in an expression, and I always regretted every time I tried it in C or Crystal. I understand this experience is pretty insignificant in comparison to many of the wizards here, but I thought I'd still share it as an opener for what I'm about to say.
The older you get, the more you'll regret not still being 13 ;-)
With this being said, I'd encourage everyone to take a bit of a step back: what exactly are people looking for in PEP 572?
I see two main goals:
Most other use cases would significantly hurt readability and seem pretty rare.
I haven't been much impressed by suggested uses outside conditional contexts either.
Now let's break down the top one:
So there are roughly three main goals here overall. Now, are there better ways to solve these? ... C++ has recently solved the if condition by allowing declarations inside the conditions:
But C++ has always had assignment expressions. This:
if (auto a = 123; a != 456) {
is solving a different (albeit related) problem: that C/C++ require declaring variables before use. Python doesn't. They could have done the same via, .e.g,,
{ auto a = 123; if (a != 456) { ... } }
and still have had the scope of a
limited to one block.
auto-initializers in conditionals just gave a bit of syntactic sugar
for what was already easily (although with more typing) done.
Many languages have a 'let' expression (using Felix as my example):
if let a = 1, b = 2 in a == b then
I don't read Felix, but I assume the _scope_ of a
&
b
there ends
immediately before the "then". If the names can't be used in the
_body_ of a Python if
(or while
) block, it's essentially
useless
to allow binding names for use solely in the conditional test.
So it would help if you picked "real Python examples" from the many
other earlier messages in these threads. Python expressions can't
span Python statement boundaries - only Python blocks can do that. A
form of let
that _would_ work would be block-structured:
let m = regexp.match(pattern. line) in:
if m:
print(m.group(0))
That solves "a scope problem" the current version of the PEP gave up on, but in all other respects seems a step back from the current:
m = regexp.match(pattern, line)
if m:
print(m.group(0))
Swift has taken a bit of a hybrid between the above two:
if let a = 1, b = 2, a == b {
That seems plain incoherent ;-)
Now, what's the common theme here? Declarations should be separate from expressions. We've got languages that range from baggage-filled to functional to a bit of all of the above, and none of them have added assignment inside an expression.
C++ and C have always had assignment expressions . Ditto Java, Javascript, Perl, Icon, ... (many, many others). I don't see a good reason to grant that Felix and Swift are necessarily improvements over the former (with the exception of Icon, which I'm merely fond of) very widely used languages.
The argument is roughly the same across all boards: you're putting major but easy-to-miss side effects in the midst of expressions that seem pure.
All this is to say: I'd really encourage everyone here to think a bit more about why exactly you want this feature, and then think if there's really no better way. Any solution that separates declarations would be far more readable, (arguably) more Pythonic, and play more nicely with the new-ish typing features to boot
People have been trying for years. If you come up with a realistic (for Python) idea, that's great - share it! But it's probably better suited to python-ideas than python-dev.
...
On 2018-04-25 19:36, Ryan Gonzalez wrote:
By now we've searched over the current proposal in excruciating detail.
However, there were two good questions in this message which I haven't seen addressed yet:
- How are other modern languages solving this issue?
- How does this new construct intersect with typing functionality?
-Mike
Mike Miller wrote:
- How are other modern languages solving this
issue?
In all the languages I can think of that allow assignments in expressions, there is only one assignment operator -- a stand alone assignment is just a bare assignment expression.
But those languages were all designed that way from the start. I'm not aware of any that began by forbidding assignment in expressions and then added it later.
-- Greg
[Mike Miller]
- How
are other modern languages solving this issue?
[Greg Ewing greg.ewing@canterbury.ac.nz]
In all the languages I can think of that allow assignments in expressions, there is only one assignment operator -- a stand alone assignment is just a bare assignment expression.
Pretty much so, but I don't know what "modern" means to Mike. The R language may set a record for, umm, innovation here:
""" There are three different assignment operators: two of them have leftwards and rightwards forms.[1] """
So there are 5 assignment operator spellings in R:
= <- -> <<- ->>
Note that the link doesn't tell the whole story either; e.g., they don't all have the same precedence level. And, in addition to the 5 infix spellings shown above, there are also prefix (looks like a 2-argument function call) spellings.
Back on Earth ;-) , I think it's worth it to point out that only languages (with assignment expressions) aping C use "=" for assignment and "==" for equality. That was a Really Bad Idea that all other (not aping C) languages I know of avoided.
But I'm not sure any of this is relevant to what Mike meant by "this issue".
But those languages were all designed that way from the start. I'm not aware of any that began by forbidding assignment in expressions and then added it later.
Me neither. It's certainly the case that Guido would not have designed a language that aped C's poor decision here. At its very start, Python used "=" for both assignment and equality testing (and == was a syntax error). So I think it's evident that, at the time, he didn't envision ever adding assignment expressions.
[1] https://www.rdocumentation.org/packages/base/versions/3.5.0/topics/assignOps
On Thu, Apr 26, 2018 at 09:36:48AM -0700, Mike Miller wrote:
However, there were two good questions in this message which I haven't seen addressed yet:
- How are other modern languages solving this issue?
- How does this new construct intersect with typing functionality?
What counts as a modern language? Less than five years old? Less than fifty years old? Are Javascript, Ruby and R modern? They all support assignment as expressions.
I think Koitlin, Rust and Go prohibit assignment as expressions.
Swift assignment evaluates as Void (equivalent to None in Python, I guess), so you can use assignment in an expression but it returns nothing and only operates by side-effect.
As far as type hints go, I think that if you need explicit type hints in the middle of an expression, it's a bad idea and you ought to pull it out as a separate statement. That applies regardless of whether that expression involves binding or not.
-- Steve
Rust has a few syntactic ways to accomplish the same thing, though. I think match expressions are used for the equivalent of conditionals that carry the condition value into the body of the expression, and all blocks return the result of the last statement, so you can do things like:
let mut x; while { x = foo(); x } { bar(x); }
I don't know if that's idiomatic Rust (and I wrote it on a phone and didn't check to be sure it compiles), but it does more or less solve the problem of assignment in a control flow condition.
On April 27, 2018 12:58:16 AM UTC, Steven D'Aprano steve@pearwood.info wrote:
On Thu, Apr 26, 2018 at 09:36:48AM -0700, Mike Miller wrote:
However, there were two good questions in this message which I haven't seen addressed yet:
- How are other modern languages solving this issue?
- How does this new construct intersect with typing
functionality?
What counts as a modern language? Less than five years old? Less than fifty years old? Are Javascript, Ruby and R modern? They all support assignment as expressions.
I think Koitlin, Rust and Go prohibit assignment as expressions.
Swift assignment evaluates as Void (equivalent to None in Python, I guess), so you can use assignment in an expression but it returns nothing and only operates by side-effect.
As far as type hints go, I think that if you need explicit type hints in the middle of an expression, it's a bad idea and you ought to pull it out as a separate statement. That applies regardless of whether that expression involves binding or not.
-- Steve
Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/paul%40ganssle.io
On Fri, Apr 27, 2018 at 10:52 AM Paul G paul@ganssle.io wrote:
Rust has a few syntactic ways to accomplish the same thing, though. I think match expressions are used for the equivalent of conditionals that carry the condition value into the body of the expression, and all blocks return the result of the last statement, so you can do things like:
let mut x; while { x = foo(); x } { bar(x); }
Go is similar to Python; it's doesn't allow assignment in expression. And Go has similar syntax like above;
for x := foo(); x { bar(x) } if err := baz(); err != nil { return err }
I like Go and I think this syntax can be ported to Python. But it help only if/while statements. It doesn't help list comprehension. And Go doesn't have list comprehension.
Sorry all, wasn't specific enough.
By "modern" I mean the last decade perhaps. New languages that have had a chance to look at the older generations and choose their best ideas, while leaving behind the rest.
Personally I thought of Swift (Ryan mentioned), Kotlin, Rust, and perhaps Go, though Go wasn't focused on breaking new ground outside of ease of concurrency. I don't know R or Felix at all, but sound interesting. Nim is another I'm vaguely aware of. They surely have given some thought to the issue.
One thing that jumped out at me is that most replies here jumped to the question of whether they supported assignment-expressions, but that is only one potential solution. To be more clear, I wondered how did they solve "the problem itself?" Was their solution different? Ryan somewhat alluded to that, but I'd like to dig in a bit on that part.
In contrast, in many of the other threads I heard, "C, C++, C#, Java, etc do assignment-expressions, they're useful and not so hard to learn." Ok that's reasonable, but where is the industry headed? Python deferred long enough that we don't necessarily have to choose a classic solution.
So, it sounds like many of the new generation of languages are not embracing these expressions everywhere but rather letting folks do an assignment right in the statement where their use case applies, if, while, maybe comprehensions. Is that accurate?
Looks like I've got some homework to do, haha.
-Mike
On 2018-04-26 17:58, Steven D'Aprano wrote:
What counts as a modern language? Less than five years old? Less than fifty years old? Are Javascript, Ruby and R modern? They all support assignment as expressions.
I think Koitlin, Rust and Go prohibit assignment as expressions.
Swift assignment evaluates as Void (equivalent to None in Python, I guess), so you can use assignment in an expression but it returns nothing and only operates by side-effect.
As far as type hints go, I think that if you need explicit type hints in the middle of an expression, it's a bad idea and you ought to pull it out as a separate statement. That applies regardless of whether that expression involves binding or not.
On April 27, 2018 12:16:09 AM Mike Miller python-dev@mgmiller.net wrote:
Sorry all, wasn't specific enough.
By "modern" I mean the last decade perhaps. New languages that have had a chance to look at the older generations and choose their best ideas, while leaving behind the rest.
Personally I thought of Swift (Ryan mentioned), Kotlin, Rust, and perhaps Go, though Go wasn't focused on breaking new ground outside of ease of concurrency. I don't know R or Felix at all, but sound interesting. Nim is another I'm vaguely aware of. They surely have given some thought to the issue.
One thing that jumped out at me is that most replies here jumped to the question of whether they supported assignment-expressions, but that is only one potential solution. To be more clear, I wondered how did they solve "the problem itself?" Was their solution different? Ryan somewhat alluded to that, but I'd like to dig in a bit on that part.
In contrast, in many of the other threads I heard, "C, C++, C#, Java, etc do assignment-expressions, they're useful and not so hard to learn." Ok that's reasonable, but where is the industry headed? Python deferred long enough that we don't necessarily have to choose a classic solution.
So, it sounds like many of the new generation of languages are not embracing these expressions everywhere but rather letting folks do an assignment right in the statement where their use case applies, if, while, maybe comprehensions. Is that accurate?
This is basically what I was trying to say, except far better worded...
Looks like I've got some homework to do, haha.
-Mike
On 2018-04-26 17:58, Steven D'Aprano wrote: What counts as a modern language? Less than five years old? Less than fifty years old? Are Javascript, Ruby and R modern? They all support assignment as expressions.
I think Koitlin, Rust and Go prohibit assignment as expressions.
Swift assignment evaluates as Void (equivalent to None in Python, I guess), so you can use assignment in an expression but it returns nothing and only operates by side-effect.
As far as type hints go, I think that if you need explicit type hints in the middle of an expression, it's a bad idea and you ought to pull it out as a separate statement. That applies regardless of whether that expression involves binding or not.
Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/rymg19%40gmail.com
-- Ryan (ライアン) Yoko Shimomura, ryo (supercell/EGOIST), Hiroyuki Sawano >> everyone else https://refi64.com/
On 04/27/2018 05:35 AM, Ryan Gonzalez wrote:
[snip]
Ryan, the quoted text in your emails is not being marked as such, meaning that the entire email appears to be from you. This makes it really difficult to pick out your responses.
I would really appreciate it of you could figure out why that is happening and resolve it. (I have no clue so can't offer any ideas.)
Thanks.
-- ~Ethan~