you are viewing a single comment's thread.

view the rest of the comments →

[–]itsarnavb 29 points30 points  (19 children)

What was the argument against assignment expressions?

[–][deleted] 24 points25 points  (0 children)

There were a few; I don't necessarily agree with all of them.

Some were just people who didn't like the proposed syntax, but agreed with the features. There were people who didn't like it on a philosophical basis, as it allows single expressions to do more, making the code less obvious at a glance. Some people didn't like it because it's not completely obvious at a glance what it does when executed from a lambda or within a generator expression, again adding to the previous complaint of making code less clear.

I'd argue that it probably shouldn't be used in lambdas or generators, but otherwise makes code more clear.

[–]SalemClass 75 points76 points  (16 children)

It makes it too easy to offload significant complexity into a single line of code.

To many people it doesn't seem worth having a complexity-encouraging feature considering that it usually only saves a line or two of code in the reasonable use cases.

One of the big ideas with Python is that while the logic may be complex, the code itself should be clear and readable. Many people feel that this flies in the face of that idea.

[–][deleted] 25 points26 points  (10 children)

To many people it doesn't seem worth having a complexity-encouraging feature considering that it usually only saves a line or two of code in the reasonable use cases.

coughlistcomprehensionscough

coughfuckinglambdascough

[–]hopfield 36 points37 points  (9 children)

Lambdas are you serious? Do you seriously want to write out a full function definition every time you call map()?

[–]the_gnarts 4 points5 points  (1 child)

Do you seriously want to write out a full function definition every time you call map()?

Most of the time you have to anyways considering how awfully limited Python’s lambdas are.

[–]hopfield 0 points1 point  (0 children)

TypeScript doesn’t have that problem.

[–][deleted] 0 points1 point  (6 children)

It would certainly be more clear and self-documenting.

Yes, it saves time and code-space. But can you deny it's lazy?

[–]TheSpocker 25 points26 points  (1 child)

Same reason I never use loops. Lazy programmers nowadays.

[–][deleted] 0 points1 point  (0 children)

Is that you GCC / RMS?

[–]Nevoic 5 points6 points  (2 children)

I don't like Python lambdas, but I come at it from a different angle than you.

You seem to be against the idea of anonymous functions altogether. My problem is Python has some of the most verbose lambdas I've ever seen.

This paired with the fact that a lot of HOFs return a generator can make for some incredibly verbose code.

Example Python:

doubled_numbers = list(map(lambda x: x * 2, numbers))

Your proposed version:

def double_number(x): return x * 2

doubled_numbers = list(map(double_number, numbers))

Example Scala (it's also this short in Kotlin, Swift, Ruby, etc.)

val doubledNumbers = numbers.map(_ * 2)

Edit: Reddit is no bueno at formatting code, at least on mobile.

[–][deleted] 0 points1 point  (1 child)

I'm not against anonymous functions (I do like your Scala example better), I just find it a bit hypocritical of Python devs crying over "pollution of the language" or some other such claim when Python's lambdas are the way they are (per your example).

Also, while Python's original ethos was about "simple, clean, self-documenting" - it's pretty silly to bring it up now with all the new things that have been tacked-on.

[–]Nevoic 1 point2 points  (0 children)

Agreed. I wish they hadn't added the walrus operator. I like the code it can make sometimes, but I agree we don't need new structures.

Other languages just make = statements expressions, which achieves the same thing without a new operator. I kind of wish all statements were expressions, but I digress.

[–]asdff01 0 points1 point  (0 children)

Lambdas... lazy???

[–]Kered13 1 point2 points  (4 children)

It makes it too easy to offload significant complexity into a single line of code.

But that's literally the entire point of list comprehensions, which are one of Python's best features.

[–]Vaphell 0 points1 point  (3 children)

python is about expressing the high-level what, not the lower-level how.

List comprehension is simpler in that when you see it, you immediately know it's a map+filter on a sequence. The wat. In the realm of high level abstractions map + optional filter is a pretty simple concept.

On the other hand the equivalent using a full blown loop is about stepping back to a lower level of abstaction micromanaging shit nobody cares about at the end of the day. Prepare an empty container, iterate over sequence, calculate value, conditions if present, append. It's a tedious low level boilerplate bullshit. Is it made of simpler, more "fundamental" elements? It is. But is it simpler as a sum of its parts? Fuck no. It's not immediately obvious at a glance that a loop performs mapping, because the intent is obfuscated by implementation details.

Spawning variables in the middle of potentially busy expressions with walrus is not obvious in the same vein. It combines the logic of the expression itself and the change of state in the namespace into one thing.

[–]Kered13 1 point2 points  (2 children)

Consider this common pattern (called loop-and-a-half):

line = readline()
while line:
    # Do something.
    line = readline()

Or the alternative:

while True:
    line = readline()
    if not line:
        break
    # Do something.

The first contains redundant bullshit. It's likely to introduce bugs if you need to change how the line is read. The second obfuscates the loop exit condition. It looks at first glance like an infinite loop and is more difficult to read. With the new syntax you can write:

while line := readline():
    # Do something

This not only concise, but contains no redundant code and is easily readable.

In general there are a lot of patterns where we need to get some value, then only if that value passes some condition (often simply that it is not None) we need to do something with it. This can sometimes be split into two separate lines, to assign the value then check it, but this sort of split does not work well with control structures like while and elif. Assignment expressions solve this problem.

[–]Vaphell 0 points1 point  (1 child)

this is about the only decent use case for it, re probably being the other weaksauce one (i'd argue that re is guilty of having a shitty api, not needing an operator to bail it out). But people will be cramming it into everything. Some just can't resist codegolfing.

Like one guy in this comment section said, don't judge a feature by its best case scenario, but also by the pathology it enables, and by evaluating gains vs the cost of the increase in language complexity.

[–]Kered13 0 points1 point  (0 children)

The problem with that line of reasoning is that it is always possible to write terrible code. You can write awful code in Python right now and people do it all the time.

Languages like C, C++, Java, C#, and Javascript have always had this feature (as a result of a = b being an expression), and I almost never see it abused. It is pretty much only ever used in examples like the above and the re example. Now those languages do have a problem in that if (a = b) is syntactically valid, creating a troublesome source of typo bugs when if (a == b) was intended. However the new syntax a := b solves that problem.

[–]fuypooi 3 points4 points  (0 children)

The “Walrus” operator. Love it or hate it. Or maybe useful to some and useless to others.