Hacker News new | past | comments | ask | show | jobs | submit login

Maybe you'll prefer

  return 
    (a < b) ? -1 :   // a smaller
    (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?


Nested ternary is obvious when formatted as above, and it's dramatically more compact. Try it for a bit, you'll see how simple and clear it is.


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 it's dramatically more compact

Why do I want that?


> 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 add to the other poster: the more context you can fit on your screen, the less scrolling, jumping you need to do to understand a program's behaviour. Compactness that doesn't sacrifice readability speaks for itself. The code sample we're discussing is compact and very readable.


>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 smaller
    (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 if(a > b)
    return 1;
  else
    return 0;
which isn't quite true. It's actually:

  if(a < b)
    return -1;
  else 
    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.


> It's still hard to read if you inline multiple ternary operators the way OP suggested is easy.

I disagree. The ternary version is much easier to read than your if-else. If-else statements can feature compound statements and side-effects where the ternary version is simpler because it only returns a value. There are fewer corner cases to consider.

> 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.

It adds no complexity. It's significantly easier to understand than if-else.

> which isn't quite true. It's actually:

Right, there's literally no semantic difference between those two.

> No - but there is a subtle semantic difference that you have to stop to consider when you're scanning this code.

You really don't. There's nothing special to consider, no corner cases. It's literally condition-on-left-value-on-right.


But those two pieces of code are parsed exactly the same way in most languages--the only difference is the newline between `else` and `if`


Compactness and readability are related, in the sense that your working memory also works somewhat in terms of lines of code.

There's a natural trade-off in the sense that in order to make something more compact, you have to rely on the context to provide whatever information you remove. For example, the ternary pattern of chaining ?:'s. You have to be used to it. However, once you know it, the more compact pattern works fairly well.


With the ternary it's more obvious that you're always putting the result in the same place.


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


Ternary isn't the same as a branch and you want your this simple comparison function to get inlined every time


> Ternary isn't the same as a branch

It should be. The C ternary is just an expression-oriented version of if/elseif/else.

Languages with a functional bend simply make if/elseif/else an expression in the first place e.g. in Rust it'd be

      return 
        if a < b { Ordering::Less }
        else if a > b { Ordering::Greater }
        else { Ordering::Equal }
Though obviously that specific version is an overly complex way of writing:

    return a.cmp(b);


Most compilers will probably reduce if-else and ternary to the same instructions. If it's a conditional value binding it might not be a branch but a conditional move instruction.


i find it really odd that of all the knocking back and forth on this thread, you are the only person to suggest that using symbolic values for 'greater than', etc, improves readability.


It's not really my suggestion though, it's just what Rust does (inherited from Haskell, interestingly enough OCaml does not do that) and I figured I'd post "proper" rust code rather than a bastardisation.


If you need to optimize to that extent, then do whatever you need to do. In the vast majority of applications it makes no difference.


This is a beautiful way to express multiple ?: expressions.


I don't agree. It occludes the nested structure.

We can regard the condition as the head of a clause, and the ? and : as heads of sub-clauses:

   A ? B
     : C
which leads to:

   return a < b ? -1
                : a > b ? 1
                        : 0;


What you're writing here is equivalent to insisting that people do:

  if (a < b) {
    return -1;
  } else {
    if (a > b) {
      return 1;
    } else {
      return 0;
    }
  }


Nope, since I haven't added any non-whitespace characters, rather it is like insisting that people do:

  if (a < b) {
    return -1;
  } else
    if (a > b) {
      return 1;
    } else {
      return 0;
    }
Unlike your perfectly formatted code there, this has a bit of a visual problem: a one-liner consequent is fully braced, whereas a multi-line alternative isn't.

Ternary operators are different. They have confusing nesting and do not support the equivalent of the "if/else ladder" pattern very well.


> It occludes the nested structure.

The nesting is irrelevant to understanding the semantics, so this objection doesn't fly. The idiom is basically just a truth table with conditions on the left and the matching value on the right. You read it left-to-right, top-to-bottom, just like all other code. The first condition on the left that matches returns the value on right-hand side.


> The nesting is irrelevant to understanding the semantics

The nesting is absolutely relevant to producing the semantics.

The following uses deceptive whitespace to suggest a nesting that is contrary to the actual nesting, interfering with understanding:

  if (foo)
    if (bar)
      xyzzy();
  else
    flop();
The ternary operator A ? B : C is the goofy invention of demented mind. In nested situations, it is mind-bendingly unreadable. It behooves us to style it in a way that reveals the abstract syntax tree structure.

In C, I would in fact recommend:

  #define if3(a, b, c) ((a) ? (c) : (c))

  return if3(a < b, -1, if3(a > b, 1, 0));
Now we can have it in one line, yet it's clear.


> The following uses deceptive whitespace to suggest a nesting that is contrary to the actual nesting, interfering with understanding

Fortunately, the ternary pattern doesn't exhibit this problem. So again, this objection doesn't fly.


still less clear




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: