Most active commenters
  • jcelerier(4)
  • TooBrokeToBeg(3)
  • arkadiytehgraet(3)

←back to thread

2024 points randlet | 33 comments | | HN request time: 1.667s | source | bottom
Show context
js2 ◴[] No.17516019[source]
Background ("PEP 572 and decision-making in Python"):

https://lwn.net/Articles/757713/

replies(2): >>17516132 #>>17516693 #
jcelerier ◴[] No.17516132[source]
> The problem with the C-style of assignments is that it leads to this classic error: if(x = 0) {...}

yeah, if you code on 20 years old compilers with no warnings. GCC 4.1 warns about this (with -Wall) and Clang 3.4 warns about this too, without any warning flag.

replies(4): >>17516174 #>>17516220 #>>17517715 #>>17518178 #
1. Waterluvian ◴[] No.17516174[source]
I think that having strong opinions on how others should be developing software is how communities become toxic like this.

"Shooting yourself in the foot is your fault for not using a linter that detects accidental misuse of assignment!"

replies(3): >>17516217 #>>17516742 #>>17516875 #
2. jcelerier ◴[] No.17516217[source]
> I think that having strong opinions on how others should be developing software is how communities become toxic like this.

Depends on what you think the answer to "is programming an art or a science" is. People who build bridges are absolutely subject to "strong opinions" on how to build bridges. I am of the opinion that shipping software to others when under a contract without using all the facilities available to prevent problems - linting, static type checking, etc - should be considered at best a breach of contract and ideally criminal negligence.

replies(4): >>17516414 #>>17516463 #>>17516818 #>>17520374 #
3. Waterluvian ◴[] No.17516414[source]
You're right. There are times where being right is absolutely imperative.

Maybe it's a know it when you see it kind of thing. When the debate isn't killing people, it's potentially inconvenient extra coding by a developer, and to appreciate the immense social cost those debates can have.

4. icebraining ◴[] No.17516463[source]
Programming languages are not just used for shipping software to others when under a contract. Specially Python, which is often used as a teaching language.
5. TooBrokeToBeg ◴[] No.17516742[source]
I'm still puzzled to why would a compiler allow assignment in an explicit conditional (outside of loop syntax). It's like a baked-in blindspot that most people just want to ignore for some reason. Some languages actually guard against this well enough (eg Kotlin) and say "don't". Even with guards in place, it's not all that complicated to work around in the edge cases where you might want to do it.
replies(5): >>17517091 #>>17517115 #>>17519127 #>>17519910 #>>17519933 #
6. woah ◴[] No.17516818[source]
Thinking that linting and static typing will stop all errors is foolish (although I prefer both, myself). Cargo culting "best practices" is often useless, and is sometimes used as a crutch by developers who are bad at the much more important and much less quantifiable things, like code readability and architectural simplicity.

Wanting your pet coding preferences to be enforced by criminal law is a sadomasochistic fantasy.

replies(2): >>17517481 #>>17520898 #
7. Dayshine ◴[] No.17516875[source]
Linter?

You mean compiler right? The compiler should be warning for things like this, not relying on 3rd party tools.

So, yes, if you're using a custom compiler, you kinda are to blame for shooting yourself in the foot. Just use the official binaries!

replies(2): >>17517020 #>>17518135 #
8. dvlsg ◴[] No.17517020[source]
Depends on the language. Javascript, for example, would use a linter for this warning.
9. arkadiytehgraet ◴[] No.17517091[source]
Funny you should mention Kotlin; while I like the language a lot, I believe this particular feature would be of immense help in the following scenario:

Imagine you have a sealed class Foo, with `class Bar(x: String) : Foo()` and `Baz() : Foo()`.

Now, imagine you have a method, returning an object of type Foo: `fun foo(): Foo`

And you want to pattern match on the result of this method:

  when(foo()) {
      is Bar -> ...
      is Baz -> ...
  }
Now, the problem is: how do you access String field x in the first branch? The only way to do it now is to extract the methos call into redundant local variable, and then pattern match it instead of `foo()` directly as I did above.

Now imagine Kotlin had that feature; then we could just do the following:

  when(foo = foo()) {
    is Bar -> foo.x
    is Baz -> ...
  }
replies(2): >>17517234 #>>17520246 #
10. kelnos ◴[] No.17517115[source]
Because assignment is an expression. It has nothing specifically to do with the position being a conditional.

Conditionals need an expression, and assignment fits the bill, so it works.

replies(3): >>17518108 #>>17519195 #>>17520103 #
11. bpicolo ◴[] No.17517234{3}[source]
One option is match statements. Great way to make this sort of inline assignment unnecessary
replies(1): >>17517267 #
12. arkadiytehgraet ◴[] No.17517267{4}[source]
Could you please elaborate more on what you mean by match statements? Is it an already existing feature of Kotlin?
replies(1): >>17517291 #
13. bpicolo ◴[] No.17517291{5}[source]
Ah, I guess `when` is literally Kotlin's equivalent of match.

What I'm thinking of here is Rust's match statements, which do give you the ability to make use of those intermediary values by making use of Rust's enum type.

https://doc.rust-lang.org/book/second-edition/ch06-02-match....

replies(1): >>17517337 #
14. arkadiytehgraet ◴[] No.17517337{6}[source]
I see; I agree that proper pattern matching would indeed solve that as well, as e.g. Scala does.
15. jcelerier ◴[] No.17517481{3}[source]
> Thinking that linting and static typing will stop all errors is foolish (although I prefer both, myself).

Thinking that putting a seatbelt will prevent death in a crash is foolish, and yet they are still mandatory

replies(1): >>17518410 #
16. KSteffensen ◴[] No.17518108{3}[source]
Why is assignment an expression and not a statement? Why should an assignment evaluate to a value?
17. KSteffensen ◴[] No.17518135[source]
It's not that easy for the compiler to provide these warnings when the language is interpreted rather than compiled
replies(1): >>17519210 #
18. mkesper ◴[] No.17518410{4}[source]
Here you are very wrong. Look at https://www.cdc.gov/motorvehiclesafety/seatbelts/facts.html#... or https://en.wikipedia.org/wiki/Seat_belt
replies(1): >>17518926 #
19. jcelerier ◴[] No.17518926{5}[source]
that's exactly what I mean. Seatbelts won't save you every time but they save you enough times that they are mandatory.

> In another study that examined injuries presenting to the ER pre- and post-seat belt law introduction, it was found that 40% more escaped injury and 35% more escaped mild and moderate injuries.[83]

I don't know how many bugs can use of all possible explicit typing and compiler warnings avert but I'd wager that it would be at least as high a percentage.

replies(1): >>17519733 #
20. shakna ◴[] No.17519127[source]
It's handy in C for guarding parts of the language, as you often have to check return values anyway.

    if(malloc(10000 * sizeof foo) == NULL) {
      // Error processing
    } // No need for an else branch here.
replies(1): >>17519309 #
21. TooBrokeToBeg ◴[] No.17519195{3}[source]
> Because assignment is an expression. It has nothing specifically to do with the position being a conditional.

No, but it has a lot to do with the way humans write code. This is the source of the bug, not the logic. eg Why bother having whitespace that the compiler can't use (typically)? Human readability.

The concession to not take into account human failing, is pathological.

22. TooBrokeToBeg ◴[] No.17519210{3}[source]
The compiler can do anything a linter can do. Multi-pass multithreaded compilers are not unheard of. eg While compiling to temporary storage, I do a linting in another thread. At the end, check for successes and move the artifacts into the output directory.
replies(1): >>17519893 #
23. the-dude ◴[] No.17519309{3}[source]
Missing assingment.
replies(1): >>17519481 #
24. shakna ◴[] No.17519481{4}[source]

    int success = NULL;

    if(success = malloc(...)) {
    }
    if(success = malloc(...)) {
    }
    if(success = malloc(...)) {
    }
replies(1): >>17519737 #
25. wrmsr ◴[] No.17519733{6}[source]
And as a former motorcyclist the idea of putting a seatbelt on a bike is terrifying, but under the umbrella of 'mandatory' I'd have to risk getting cut in half in a fender bender 'because that's how it's done'. If you blindly follow guidelines without understanding why they were put in place and when they should be circumvented you do more harm than good. In this context specifically, a python thread, I've not even found formatters that 'just work' in python to the degree that they do in java - I get and support significant whitespace but that combined with the crazy calling convention frequently lead me to just have to suffix spans of lines with noqa because I'm communicating to the reader something that a dumb bot doesn't understand. And that's not even getting into the heavier stuff, I type annotate everything but mypy is beyond useless for my relevant codebases - it no longer just outputs walls of useless noise it straight up crashes, from the most minimal use of even descriptors much less metaclasses. Tools and policies are essential but at the end of the day humans and situations are still currently authoritative.
26. slavik81 ◴[] No.17519737{5}[source]
That will result in undefined behaviour if the value returned by malloc is greater than INT_MAX. If you really need an integer, use intptr_t. But, generally it makes more sense to just use a pointer.

    char* p = NULL;
    if (p = malloc(...)) {
      ...
    }
27. TwelveNights ◴[] No.17519893{4}[source]
What the poster means is that a compiler may not be as applicable to interpreted languages.
28. wool_gather ◴[] No.17519910[source]
Well, if you have the concept of Maybe/Optional, it's quite handy to have a conditional binding as control flow (as in Swift):

    guard let value = myOptional else {
        // Handle absence
    }
    // Use value
Or

    if let value = myOptional {
        // Use value
    }
29. emmelaich ◴[] No.17519933[source]
Read Tim Peter's essay on the end of the PEP 572.

It's very good.

30. hinkley ◴[] No.17520103{3}[source]
The other partial fix is to stop allowing truthy conditionals. Only allow Boolean values and the only time you it wrong is when you’re assigning to booleans.
31. bjz_ ◴[] No.17520246{3}[source]
In Rust and Haskell you can do:

    match foo() {
        Bar @ foo => foo.x,
        Baz => ...,
    }
32. jodrellblank ◴[] No.17520374[source]
I feel like you could have written this https://jjj.blog/2016/08/todays-software-is-terrible/
33. vehementi ◴[] No.17520898{3}[source]
> Thinking that linting and static typing will stop all errors is foolish

Did you reply to the wrong post?