Live data from Hacker News

Clear is better than clever [pdf]

dave.cheney.net

261–270 of 335 posts

Re: Clear is better than clever [pdf]

#261

Earlier quoted context omitted.

You see the problem though, I need to try it and practice it to see how simple and clear it is. I can write code that I can easily understand. I can write terse, clever code that I can easily understand. But I want to write code so that the next person can also easily understand it. More importantly, code that's easier to understand has less chance of getting buggy when it inevitably gets rfactored or extended. >and…

> You see the problem though, I need to try it and practice it to see how simple and clear it is. You need to practice it to overcome your skepticism resulting from your ingrained habits that prejudice you against it, not because it's inherently unreadable. It literally takes 5 seconds to understand the idiom: conditions/guards on the left, value on the right. It's essentially a truth table. > Why do I want that? To…

>It literally takes 5 seconds to understand the idiom

I understand how ternary operators work. It's still hard to read if you inline multiple ternary operators the way OP suggested is easy. It adds cognitive complexity, and hides bugs because your brain will fill the details on what it assumes it does, versus the subtleties of what it actually does.

In fact, it is obviously so confusing that to make it work someone suggested the introduction of white-space and multiple lines, as follows:

  return
    (a  b) ?  1 :   // a greater
               0;    // equal
And they still got it subtly wrong, because the semantics of their 'fix' makes it seem like it is the equivalent of:

  if(a  b)
    return 1;
  else
    return 0;
which isn't quite true. It's actually:

  if(a  b)
      return 1;
    else
      return 0;
Will this make a difference in this case? No - but there is a subtle semantic difference that you have to stop to consider when you're scanning this code.

Re: Clear is better than clever [pdf]

#262

It's interesting that the comparator function is one of the examples, because that's something which shows how people often confuse verbose with clear ; I think it's best written in a single line: return a b ? 1 : 0; That's one line, compared with the 10(!) of his proposed method using a switch statement. Having worked with some "modern" codebases, I think verbosity is a bigger problem that's become especially preval…

Couldn't you just break the ternary up?

  if a == b { return 0 }

  return a > b ? 1 : -1
Also it would be ~7 lines, not 10?

  if a > b {
    return 1
  } else if a 

Re: Clear is better than clever [pdf]

#263
post #39

It's interesting that the comparator function is one of the examples, because that's something which shows how people often confuse verbose with clear ; I think it's best written in a single line: return a b ? 1 : 0; That's one line, compared with the 10(!) of his proposed method using a switch statement. Having worked with some "modern" codebases, I think verbosity is a bigger problem that's become especially preval…

Fully agree! Combinations of if/else can seriously damage readability and maintainability. I (all the time) face verbose code that pretend to be readable and that requires lots of attention just to find out you are setting a single variable across 10-20 lines. Example: if (cond1) { myVar = 1; } else if (cond2) { if (cond3) { myVar = 10; } else { myVar = 100; } ... } else { myVar = defaultValue; } * huge number of lin…

About the only change I would make to your layout is to put a line break after the “?”, with the value sub-indented on the next line, to avoid “guessing” /maintaining how far to tab over the value column.

Thus, it would be layed out like an else-if chain, but without the extra verbiage, particularly the repeated assignment.

(I can’t put in a proper example from my iPad, as it wants to capitalize all the lines, etc)

Disclaimer: Ruby was very influential to me in the mid 2000s, even if I never wrote any for pay. The if (else-if...) statement in Ruby works like a ternary chain in C based languages.

Re: Clear is better than clever [pdf]

#264
post #189

Earlier quoted context omitted.

You can write it without resorting to one-line conditionals: if(cond1){ myVar = 1; } else if(cond2 && cond3){ myVar = 10; } else if(cond2 && !cond3){ myVar = 100; } else { myVar = 4; } But when I encounter this kind of situations I have other problems than code formatting anyway: with 3 conditions you have 2^3 possibilities to check: are you really really sure (!cond1 && !cond2 && cond3) should give you defaultValue…

That makes code formatting inconsistent because many prefer the other way. The VB.Net style is more compact and readable in my opinion: if cond1 then myVar = 1 else if cond2 and cond3 then myVar = 10 else if cond2 and not cond3 then myVar = 100 else myVar = 4 end if The VB.Net style also makes it easier to identify mismatched blocks because the "enders" are named differently. (One can also put the assignment on the s…

You assigned “myVar” in every branch, right? Let me reread that again to make sure you really are assigning myVar in every case.

That’s a problem. One I’ve seen all too often, but a problem, nonetheless.

Re: Clear is better than clever [pdf]

#265

Earlier quoted context omitted.

My favourite solution to this problem is how rust does it. In rust every block can evaluate to an expression, so if/else is the ternary operator. let x = if cond1 { expr1 } else if cond2 && cond3 { expr2 } else { expr3 }; It’s more verbose this way (‘?’ Vs ‘else if’) but there’s no question of readability because it’s just if/else. You can format it however you like, and add statements into the blocks later if you ne…

Very lispy :-) Some would say top-level blocks returning the last value in the block is an anti-pattern, because functions which aren't meant to return a value end up leaking the value of the last thing called in the function, which might be another function, which called another function. Or it might be in various branches of an 'if', which aren't being examined for being an acceptable return value. Perl does this,…

(COND ...), anyone? :-)

Ruby has an if/else structure like the Rust/Lisp thing, as well. Tasty.

Re: Clear is better than clever [pdf]

#266
post #189

Earlier quoted context omitted.

You can write it without resorting to one-line conditionals: if(cond1){ myVar = 1; } else if(cond2 && cond3){ myVar = 10; } else if(cond2 && !cond3){ myVar = 100; } else { myVar = 4; } But when I encounter this kind of situations I have other problems than code formatting anyway: with 3 conditions you have 2^3 possibilities to check: are you really really sure (!cond1 && !cond2 && cond3) should give you defaultValue…

That makes code formatting inconsistent because many prefer the other way. The VB.Net style is more compact and readable in my opinion: if cond1 then myVar = 1 else if cond2 and cond3 then myVar = 10 else if cond2 and not cond3 then myVar = 100 else myVar = 4 end if The VB.Net style also makes it easier to identify mismatched blocks because the "enders" are named differently. (One can also put the assignment on the s…

Alternative solution: put the if/else block in an “IIFE” (which Go supports, just like JavaScript) and change the assignments to returns.

Re: Clear is better than clever [pdf]

#267
post #55

Earlier quoted context omitted.

Maybe you'll prefer return (a b) ? 1 : // a greater 0; // equal

What's the point? Why not just make it an if-elseif-else block and make it obvious?

Is it obvious that the same variable is assigned in every branch, though?

Re: Clear is better than clever [pdf]

#268

Earlier quoted context omitted.

If you even need to indent them then why you don't write a full if else statement instead? Nested ternaries shouldn't be used at all.

If/else chains are worse because they allow problems like this: if (cond) { var1 = x; } else if (cond2) { var2 = y; } else { var1 = z; } Did you notice the second block assigned to var2 instead of var1? Best case it’s a gotcha for anyone reading the code later. It might be a bug by the original author; we can’t tell at a glance if this behaviour was intentional. Ternaries remove this problem. The intent of the author…

True.

When in Java, I've gotten into the habit of using the final initializer to mitigate these kinds of issues, like this:

    final T var1;
    if (cond) {
      var1 = x;
    } else if (cond2) {
      var2 = y;
    } else {
      var1 = z;
    }
In this specific case, the compiler will catch the lack of initialization in the second block. It's also very helpful with a complicated/nested conditionals to guarantee that you initialize the variable through every code path.

Re: Clear is better than clever [pdf]

#269

This reminds of a quote by Nikola Tesla: “The scientists of today think deeply instead of clearly. One must be sane to think clearly, but one can think deeply and be quite insane.” I always preferred clarity over "cleverness" not just in programming, but also when say reading a book on a technical subject. Clarity evokes feeling of beauty I would dare say.

“Simplicity is a great virtue but it requires hard work to achieve it and education to appreciate it. And to make matters worse: complexity sells better.” - Dijkstra

Re: Clear is better than clever [pdf]

#270
post #23

Earlier quoted context omitted.

Meanwhile I'll write (a>b)-(a<b), which is what Python suggests after having removed cmp

No, what Python suggests is just returning the value you sort on, or a tuple of the values to sort on. cmp() is deprecated because there is seldom reason to use it anymore. E.G: Sorting words according to their number of letter is just: sorted(words, key=len) You don't return 1, -1 or 0. If you want to rank participants of a game in a dictionary of scores using names as keys and points as values, you would to: sorted…

Official docs: https://docs.python.org/3.0/whatsnew/3.0.html#ordering-compa...

> If you really need the cmp() functionality, you could use the expression (a > b) - (a < b) as the equivalent for cmp(a, b)

Post reply on HN