Live data from Hacker News

New Ways to Be Told That Your Python Code Is Bad

nickdrozd.github.io

161–170 of 262 posts

Re: New Ways to Be Told That Your Python Code Is Bad

#161
Well, he's right that it's opinionated. If I were to contribute to that project I'd opinionatedly implement the exact opposite linter, suggesting proper if blocks instead of a ternary expression.

The reason is simple: visual code structure.

A bespoke if block provides you with appropriate visual semantics that that part of the code involves a decision point.

By contrast, the ternary operator is useful when you want to visually obfuscate that fact, and make the code terser and more focused on the fact that an assignment is taking place, whose value is determined by an expression (which upon closer inspection happens to be conditional).

Yes I know that in the age of super-fat IDEs everything is but a search away, but, I've just come off from reading that other article from today about the guy who handwrites all his code.

So clearly low-level visual structure and ease of mental debugging still matters, no matter how bloated and feature-full your IDE is.

But what do I know. I still code on vim/nano.

Re: New Ways to Be Told That Your Python Code Is Bad

#162
post #143

Earlier quoted context omitted.

That's not a bad thing, long ternary chains are illegible. You should never have more than one condition in a ternary.

There are some specific shapes of chained ?: that are fairly legible. Eg c = condA ? valA : condB ? valB : defaultVal;

For Turing's sake, if you insist on chaining ternary operators, then you should always use parens instead of showboating that you cleverly-by-half memorized a particular language's obscure precedence and associativity rules.

PHP in all its glory and splendor actually originally used left-to-right instead of right-to-left associativity for the ternary ?: operator, so that expression you wrote works differently in PHP and (JavaScript or C or any other language). (Side note: notice how I used parens instead of depending on you guessing about the relative precedence of "and" and "or" in English.)

It's easy (and perfectly valid) to blame the designers of PHP for not knowing or caring or paying much attention to the syntax of the programming languages they were imitating, and doing something that stunningly stupid, but it just goes to prove that many people (especially PHP designers like Rasmus "I don't care about this crap at all" Lerdorf and typical PHP programmers) don't even have the faintest idea what the precedence and associativity of many of their favorite programming language's operators are, or what those terms even mean, and they just willy nilly cargo cult copy and paste and translate between PHP and JavaScript code examples from Stackoverflow, introducing terrible hard-to-spot bugs.

https://en.wikiquote.org/wiki/Rasmus_Lerdorf

>"We have things like protected properties. We have abstract methods. We have all this stuff that your computer science teacher told you you should be using. I don't care about this crap at all." -Rasmus Lerdorf

But the real fault lies not just with PHP for parroting C incorrectly, but with C for doing something that stupid and hard to remember and easy to get wrong in the first place.

Please always use parens for that kind of stuff, because even if YOU memorized and love to depend on and show off your knowledge of the precedence and associativity rules of the language you're using, the people reading and modifying and maintaining your code probably don't.

https://wiki.php.net/rfc/ternary_associativity

>PHP RFC: Deprecate left-associative ternary operator

>Unlike most (all?) other languages, the ternary operator in PHP is left-associative rather than right-associative. The left-associative behavior is generally not useful and confusing for programmers who switch between different languages. This RFC proposes to deprecate and remove left-associativity for the ternary operator and require explicit use of parentheses instead.

>As an example, the code

    return $a == 1 ? 'one'
         : $a == 2 ? 'two'
         : $a == 3 ? 'three'
         : $a == 4 ? 'four'
                   : 'other';
>would in most (all?) other languages be interpreted as

    return $a == 1 ? 'one'
        : ($a == 2 ? 'two'
        : ($a == 3 ? 'three'
        : ($a == 4 ? 'four'
                   : 'other')));
>which is both the useful and intuitive interpretation. In PHP, it is instead interpreted as

    return ((($a == 1 ? 'one'
           : $a == 2) ? 'two'
           : $a == 3) ? 'three'
           : $a == 4) ? 'four'
                      : 'other';
>which is generally not what was intended.

https://stackoverflow.com/questions/20559150/ternary-operato...

>Q: Can someone please explain what is happening here and why it is printing 'four'?

>A: Because your whole expression evaluates as if it was (......) ? 'four' : 'other'. Since the first element is probably something truthy, it gives you 'four'. In saner languages, where ?: has right associativity, the whole expression evaluates as if it was $a == 1 ? 'one' : (......), where if $a is not 1, you go on to test other things.

http://phpsadness.com/sad/30

>PHP Sadness: Ternary operator associativity

>The ternary operator is left-associative and therefore behaves entirely incorrectly:

https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/

>PHP: a fractal of bad design

>Unlike (literally!) every other language with a similar operator, ?: is left associative.

Re: New Ways to Be Told That Your Python Code Is Bad

#163

> But here’s the reality: most code is not complex enough to warrant while loops, and most while loops are better written as for loops. Hard disagree. Obviously, if the loop is a fixed number of iterations or iteration over a collection (which is trivial to identify by human inspection but probably not for a linter), a for loop is better but it is not uncommon to be looping until a (possibly compound) condition becom…

I've actually found that there are a number of situations where I really want: while True: ... if condition: break ... and kinda wish there was a nicer syntax for this.

And this is where I really miss Sather:

  loop
    while!(condition);
    ...
  end;
for while, versus

  loop
    ...
    while!(condition);
  end;
for do-while, and

  loop
    ...
    while!(condition);
    ...
  end;
in place of:

  while True:
    ...
    if not condition:
      break
    ...
Alas, it never really took off.

Re: New Ways to Be Told That Your Python Code Is Bad

#166
post #118

Earlier quoted context omitted.

I think I might be in the minority here that I prefer the fully laid out statements. Sure in small cases this small ternary use is great! However too many times I've seen people chain them for far too many characters just to be "on one line". We don't use one letter variable names anymore, so in the same reasoning why should we do the same to our code?

Yup; the booleans are difficult enough from a logic point of view, don't need to make it more complicated by using syntactic sugar. I strongly disagree with the author's idea that shorter is better. Clarity trumps conciseness. I'll admit that not enough conciseness can impact clarity, but there's ways and means to clean that up that don't involve clever code.

I hypothesise that the actual meaning (possibly subconscious) underlying those uses of "complicated", "syntactic sugar", and "clever code" is 'not the way I'd write it'; and that "clarity" and "clean" actually mean 'the way I would write it'.

To test whether those statements are guiding principles, or merely ad-hoc justifications, I propose the following pylint rules based on those principles:

    no-ternary-sugar:

      Replace 'x if y else z' with '{True: lambda: x, False: lambda: z}[y]()'.
      This is less concise, but improves clarity by using booleans explicitly,
      and making the delayed evaluation of the results clear; both of which are
      implicit in the 'if/else' syntactic sugar.

    no-elif-sugar:

      Replace:

        if foo:
          bar
        elif baz:
          quux
        ...
        else:
          foobar

      With:

        if foo:
          bar
        else:
          if baz:
            quux
          else:
            ...
            else:
              foobar

      This is less concise, but makes the branching structure clear, unlike the misleading
      "flat" appearance of the 'elif' syntactic sugar.

    no-special-case-patterns:

      Replace:

        if foo:
          bar
        else:
          baz

      With:

        match foo:
          case True:
            bar
          case False:
            baz

      'if/else' is syntactic sugar for pattern-matching a boolean, which is left implicit.
      Explicit matching improves consistency with other use-cases, and makes the relationship
      between branches and boolean clear, at the expense of conciseness.
      (Also applies to single-armed 'if', which will only have a 'case True:').
Of course, the combination of no-elif-sugar and no-special-case-patterns would give extreme clarity like this:

    match foo:
      case True:
        bar
      case False:
        match baz:
          case True:
            quux
          case False:
            ...
              case False:
                foobar

Re: New Ways to Be Told That Your Python Code Is Bad

#167

Well, he's right that it's opinionated. If I were to contribute to that project I'd opinionatedly implement the exact opposite linter, suggesting proper if blocks instead of a ternary expression. The reason is simple: visual code structure. A bespoke if block provides you with appropriate visual semantics that that part of the code involves a decision point. By contrast, the ternary operator is useful when you want t…

This! When reading/skimming through source code I find the structure very important to understand that a decision is being made and not just a simple variable assignment.

Sometimes more code is easier to read than shorter code. Even

Re: New Ways to Be Told That Your Python Code Is Bad

#168
post #122

> Python programmers in general have an irrational aversion to if-expressions, a.k.a. the “ternary” operator. Because the Python ternary operator is fucking backwards! Why on earth would you put the condition in the middle !? x = 4 if condition() else 5 vs.: condition() ? 4 : 5 vs. the author's own lisp example: (setq x (if (condition) 4 5)) I love ternary operators, and Lisp/ML-style if else blocks that return thing…

[deleted]

Re: New Ways to Be Told That Your Python Code Is Bad

#169
post #122

> Python programmers in general have an irrational aversion to if-expressions, a.k.a. the “ternary” operator. Because the Python ternary operator is fucking backwards! Why on earth would you put the condition in the middle !? x = 4 if condition() else 5 vs.: condition() ? 4 : 5 vs. the author's own lisp example: (setq x (if (condition) 4 5)) I love ternary operators, and Lisp/ML-style if else blocks that return thing…

I love the Python version, it reads like English. Use umbrella if raining, else wear shades.

Do you mean "use(raining ? umbrella : wear(shades))" or "raining ? use(umbrella) : wear(shades)"?

Personally I prefer FORTH, which like Yoda reads, and unambiguously puts the condition first, the IF second, the ELSE third, and the THEN last.

    FORTH ?KNOW IF
      HONK!
    ELSE
      FORTH LEARN!
    THEN
FORTH doesn't have expressions, parens, precedence, or associativity rules, it just has a stack (or rather, two stacks: operand and return; or three of you count the vocabulary search stack). ( And actually it does have parens, but they are for comments! )

Re: New Ways to Be Told That Your Python Code Is Bad

#170
post #143

Earlier quoted context omitted.

There are some specific shapes of chained ?: that are fairly legible. Eg c = condA ? valA : condB ? valB : defaultVal;

For Turing's sake, if you insist on chaining ternary operators, then you should always use parens instead of showboating that you cleverly-by-half memorized a particular language's obscure precedence and associativity rules. PHP in all its glory and splendor actually originally used left-to-right instead of right-to-left associativity for the ternary ?: operator, so that expression you wrote works differently in PHP…

Still beats APL
Post reply on HN