Live data from Hacker News

Clear is better than clever [pdf]

dave.cheney.net

241–250 of 335 posts

Re: Clear is better than clever [pdf]

#241
post #39

Earlier quoted context omitted.

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…

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…

I think its a poor example. How often you are going to write something like that in RL scenario?

In case of more complex data generation you could use supplier pattern and combine it with strategy.

No need for any if else statements at all.

Sure it requires a lot more of work but is future proof and clear.

Re: Clear is better than clever [pdf]

#242
post #93
post #90

Earlier quoted context omitted.

If someone is hired to work on your code base, presumably they know the language. They know ternarys work... If they don't then they need to learn. You can't say don't use specific language features because some devs can't be bothered to learn them.

I know ternary operators very well but I still have to think twice when I see them nested “You can't say don't use specific language features because some devs can't be bothered to learn them.” Would you say the same about C++? In my view it’s a good practice to use only a subset of a language consistently and not use all features. I have seen JavaScript code where I had to do research for half an hour before I could…

> I have seen JavaScript code where I had to do research for half an hour before I could figure out what it really meant.

My view on this has flip flopped several times during my career. I think every spec has some dusty corners that most people don’t know about, but when a situation calls for it knowing about some obscure features can make your code far more readable. Sometimes it’s better in the long run to train your team about a feature they might not know about rather than code for the lowest common denominator. This thread is a great example - I spent my first decade of programming scared of chained terneries. One day I spent a couple of hours goofing around with them, playing with different ways I could write my code and internalising their semantics. Now they seem fine. I wish I’d taken the time to do that years ago. Ten years being afraid saved me 2 hours of time learning.

One of the best programmers I worked with reads the specs of tools he uses for fun. He says specs seem daunting but you can read them in far less time than you think and there’s always some fascinating stuff in there. My HTML knowledge got way better working with him - and its funny seeing how many tools struggle with correct HTML because the authors didn’t bother actually learning it.

Some more examples: html void elements, html/body tag auto insertion, JS tagged break/continue, C/JS/etc’s comma operator.

Re: Clear is better than clever [pdf]

#243
post #78

Earlier quoted context omitted.

I would make the exception that if you judiciously indent then across multiple lines, to reflect the nested structure the way the if/else equivalent would, then they're fine. But yeah, nested ternaries on one line are impossible to follow.

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 is clearer, and (with proper formatting) there’s no gotchas for anyone reading the code later.

Re: Clear is better than clever [pdf]

#244
post #206

Earlier quoted context omitted.

This came up recently on the Swift Evolution forum (which is the official forum for discussing changes to the Swift programming language). Dave Abrahams said, “[…] I keep meeting experienced programmers (really smart people!) that have no trouble reading [a chain of if/else statements] and yet are confused by the analogous ternary construction: [a chain of ?: expressions]”. https://forums.swift.org/t/pitch-if-else-ex…

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, (like ECMAScript's 'do'), and while it's usefully concise sometimes, for API-level functions I think it's poor to accidentally leak values to the caller, that should never escape. The safe way to deal with this is an explicit void return at the end of API functions, but that's ugly and hard to remember.

I think JavaScript made the right choice in requiring explicit return from functions with blocks to return a value, with 'undefined' returned if nothing explicit is. Accidents are avoided.

Rust has taken an interesting approach of requiring a return type to be specified, which stops accidental leaks at least. Respect.

Re: Clear is better than clever [pdf]

#245

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…

IMHO this is pretty hard to read, unless I guess you work on code written this way every day (and most of us don't). It's not that I can't understand it, but it takes unnecessary extra effort and time to process. I want to be able to scan quickly throw a code, concentrating on understanding the logic behind, not on syntax itself, and that's very hard when it's written very dense like this. For me ternary operators are great when used on simple expressions, without nesting, and always with brackets around expressions to help eyes to navigate. In your example I'd always prefer if/elseif/else structure in place of this (unless there's a spaceship operator of course).

Re: Clear is better than clever [pdf]

#246

Earlier quoted context omitted.

> Is it really the state of the industry where a new person cannot learn a codebase, has no time or effort, and cannot read a single line of the language they were hired to work on, and that's the person we should build everything for? Seasoned 10x developers, titans of the industry, and all agree on simplicity and even they frequently make mistakes on easily confusable constructs such as nested ternaries (or even BS…

Or it could be that it’s subjective and there is no truly objective answer.

The mistakes that people make are not subjective. They can detect when they make a mistake, and must do so to correct it. When people make mistakes by using a syntactic construct, that's something can be measured, and people do measure it, which is one of the ways they develop syntax preferences. The problem is that we don't ever measure it in an unbiased and representative manner.

Re: Clear is better than clever [pdf]

#247

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…

If I understand correctly, what you're really advocating isn't ternary vs if/else, but expressive conditionals vs imperative conditionals. A statement that is something vs a statement that does something. Using expressions instead of imperative code that mutates state is a staple of functional programming, and is basically always preferred where possible. In some languages you can do this:

  var1 = if cond {
    x
  } else if cond2 {
    y
  } else {
    z
  }
Which in my opinion is strictly better than using a ternary, if the language supports it.

Re: Clear is better than clever [pdf]

#248
post #189

Earlier quoted context omitted.

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…

IMHO, better but it’s still confusing when you have multiple places where you name the variable. Functional programming style forces you to be more explicit and pushes you to separate out the assignment expression. In Elixir I’d do: myVar = cond do cond1 -> 1 cond2 && cond3 -> 10 cond2 && !cond3 -> 100 true -> 4 end ML languages have similar constructs.

Maybe, but that misaligns the values. I'd rather see them lined up. And often more complex logic may be added to the sub-blocks such that the simple pattern goes away. Code should be able to "degenerate well", meaning it shouldn't require lots of rework when the initial pattern fades or changes in the future. It's one of the reasons I often use If/else instead of switch/case statements.

Re: Clear is better than clever [pdf]

#249

Earlier quoted context omitted.

I guess I'm in a minority here, but I wish more non-functional languages would feature pattern matching, of the sort seen in Haskell and OCaml. [0] This language-design question is essentially a solved problem, but few new languages (outside the pure-ish functional ones) make the effort. Trivial example in OCaml: let imply v = match v with (true,x) -> x | (false,x) -> true;; [0] https://caml.inria.fr/pub/docs/oreilly…

It's becoming more popular. Kotlin, Swift and now C# 8.0 have pattern matching (well, close enough at least). I sure hope other languages take note, because you are right about it essentially being a solved problem.

Scala, too.

Re: Clear is better than clever [pdf]

#250

Earlier quoted context omitted.

how many branches/how much depth in a ternary statement would you consider to be too many/too much? Is there never going to be any level of depth in a ternary statement which you will think is perhaps too great, and want to switch to some more verbose syntax?

A lisper would say that there is absolutely no limit, and that in fact all programs should be structured like that.

To be clear, a lisper would not solve the problem by switching to a more verbose syntax, but that doesn't mean no depth is too deep. Breaking a big, deeply-nested function up into smaller ones is a perfectly lispy thing to do.
Post reply on HN