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

I have been reading HN for a long time but your comment is the first time I violently felt the need to create an account and respond. I want you to consider how significant that is. Ternaries are NEVER easier to read.



I don't want to come of as insensitive, it sounds like you've had some really bad experiences with ternaries in the past and it's important to acknowledge your experience. But I just want to say that not all ternaries are like that.

In a more serious tone, ternaries in places where they should be used, i.e. as expressions, are in my opinion much clearer to read than replacing them with an if-else statement. In my mind, an if/else block is an imperative entity that describes two different actions that could happen. Even if in reality both branches are trivial, my mind will be unnecessarily occupied with the fact that it needs to reason about code here, not just data. A ternary, on the other hand, is a declarative entity, saying that this expression takes on this or that value, usually in such a way that each branch of it maintains some invariant with respect to what's in the conditional.


> In my mind, an if/else block is an imperative entity that describes two different actions that could happen. Even if in reality both branches are trivial, my mind will be unnecessarily occupied with the fact that it needs to reason about code here, not just data

That's true in some languages. But in some languages if-else can also be used as in expression. e.g. in Rust I can write:

    let foo = if condition { "FOO" } else { "BAR" }


... which is equivalent to a ternary, hence the thesis.


Imho the problem with the ternary isn't the concept but the literal ?: symbols used for it.

So many languages use clear words like "if" and "then" and "else" and parens and curly braces for conditional statements...

But then they go full Perl and mash their faces against the keyboard when developing syntax for conditional expressions.

It's bone-headed language-design that C did wrong and everybody else continues to do wrong because C.


Yes, the : and ? are single characters that are easily lost/overlooked among the rest of the code on that line. Even worse when there are nested ternaries.


When I find a place where a complex ternary is probably the best choice, I'm a big fan of the following format, because I find it clear that each line is a new condition

  myvar = condition_1 ? value_1
      : condition_2 ? value_2
      : condition_3 ? value_3
      : value_fallback;


> where a complex ternary is probably the best choice

Under what circumstances would that happen? I've never encountered a nested ternary that wouldn't be better replaced with readable code, so now I'm wondering what experiences I've been missing. :)


I don't have an example handy, but it's useful in exactly the same cases where you would use a Lisp "cond" construct; testing a bunch of conditions one after the other. Using an "if / else if / ... / else" construct can do the same thing, but it can be less clear sometimes (both to intent and because it takes up more screen real estate, which makes understanding the overall code harder).


Readability is in the eye of the beholder.


Yes, good point. Still, when working on a shared codebase, it's good to take more potential beholders into account. I suppose if there is a common, consistent style that you can expect everyone to be familiar with, you can get used to reading a sensible amount of chained ternaries.


And, to illustrate my point, hypothetical "if statement is also conditional expression" syntax, to illustate how much more readable "ifs" are than "?:":

  myvar = if(condition_1) {value_1}
      else if(condition_2) {value_2}
      else if(condition_3) {value_3}
      else {value_fallback};


While I agree that "if statements are expressions" is a nice feature, I disagree that your version is more readable. That being said, it's readable enough that, if the rest of my team preferred it, I'd be ok using it.


I've been messing around with some code that uses:

  #define TERN(c, a, b) c ? a : b
I'm not a fan of ternaries, but that macro makes it kind of more ligible.


I don't advocate the use of this macro, but if you do use it you should really wrap the parameters and the whole expression in parentheses to avoid precedence issues:

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


Exactly, this is C macro 101.


That isn't more readable. It's non-standard. It also looks like a function call, but doesn't behave like one (in a function call, a, b, and c would all be evaluated). It's going to confuse other C programmers.

As Liquid_Fire points out, it's also probably incorrect.


You may wish to look at the Bourne shell source for other macros to make C readable.



Maybe ternaries aren't easier to read, but they make the surrounding code easier to read because they duck out of the way? Devoting several lines to what is a very quick if/else expression could be distracting I suppose. Playing devil's advocate.


It's important to note that ternaries are expressions, they evaluate to a value. When I see a ternary I know that a boolean is being mapped to a value. This is true both technically and almost always in practice.

If-statements are the wild west. Who knows what an if statement will do? An if-statement may be as simple as a ternary, or it might be a branch point and the resulting logic streams will never meet again.


We're talking C. As soon as a ternary calls a function, all bets are off what could be happening in addition to the value being computed.

And thanks to the preprocessor, any identifier could potentially be calling a function.


Hmm? Which part implies “all bets are off”?

There’s the condition (evaluated first), the true case and the false case. Only one of the cases is evaluated.

I’m assuming you were alluding to some sort of “x++ = x++ * *x++” style situation, but the ternary expression isn’t a statement and there are sequence points in between. As a bonus, the first result for “ternary operator evaluation order” gave me someone who linked to the standard [1]. Quoting from the standard that they quoted:

> The first operand is evaluated; there is a sequence point between its evaluation and the evaluation of the second or third operand (whichever is evaluated). The second operand is evaluated only if the first compares unequal to 0; the third operand is evaluated only if the first compares equal to 0; the result is the value of the second or third operand(whichever is evaluated), converted to the type described below.

[1] https://stackoverflow.com/questions/65109494/order-of-evalua...


I was not thinking about local state; you're right that the sequence points ensure an orderly evaluation there.

My point was that since ternaries can call functions, and functions can have side effects on global state, the concept of an "if" being a "statement" vs a ternary being an "expression / value" is not nearly as meaningful as it's made out to be. A ternary can trade stocks, fire a 500W laser, unlock a velociraptor enclosure, etc, just as easily as an if can.


If your very quick if/else is really quick enough, you can put it all on one line.


Meh. When sufficiently terse, ternary expressions are frequently more readable than a more verbose if/else equivalent. I would agree that ternaries can get out of hand quickly though.


What (besides the words if and else and the curly braces) makes the if/else equivalent more verbose)?


In C and C++, ternaries are frequently used on the right hand side of an assignment statement. if/else can't be used in such a context.

Here's a concrete example:

    const int min = x < y ? x : y;

    int min;
    if (x < y)
        min = x;
    else
        min = y;
Note also that this prevents variable min from being made const, unless you are using c++ and wrap the entire if/else in an immediately invoked lambda, which of course would require additional verbosity.


We can't objectively say whether they're easier to read or not. Opinions differ.

We can objectively say that ternaries are shorter and simpler however. (Simpler because they can do fewer things than an if-statement or if-expression.)


I don’t think that’s the case in gcc. https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html: “A compound statement enclosed in parentheses may appear as an expression in GNU C“

So, you can do (untested)

foo = bar ? ({a=1;b=2;}) : ({a=2;b=1;});

That’s widely supported in other compilers for compatibility reasons (https://stackoverflow.com/questions/6440021/compiler-support...)

You can also (mis)use the comma operator like this (again untested):

  foo = bar ? f(),g() : g(),f();
but that is more limited.


What if you write them like this?

  int x = (cond)
     ? 5
     : 1;


I personally prefer

    int x = (cond) ?
        5 :
        1;
Since the question mark applies to the condition and not the 5. This also highlights the 2 possiblities of the value in a more clear way. The two possible values are directly stacked with nothing in front of them.


Love the passion here on HN! :)


I am impressed that account name has gone unused, until now. :D


Only a sith deals in absolutes.


They are clear when succint, and especially for setting a value.

-- example:

var x;

if(this)

x = 10;

else

x = 11;

-- is uglier than:

var x = this ? 10 : 11;


I'd prefer something like

    printf(condition? "YES": "NO");
than something like

    if (condition) {
        printf("YES")
    } else {
        printf("NO")
    }


I am surprised about this. Very often you must duplicate a lot of the statement in each branch of the if statement, and it's not clear that those duplicated parts are exactly the same and must be exactly the same.


I like the name you chose just for this occasion




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

Search: