202X feature: Conditional Expressions

The Fortran Standards Committee is considering proposals for “Conditional Expressions”. An example:

Original code:

  IF (PRESENT(D)) THEN
    CALL SUB(A,B,C,D)
  ELSE IF (X<1) THEN
    CALL SUB(A,B,C,EPSILON(X))
  ELSE
    CALL SUB(A,B,C,SPACING(X))
  END IF

One proposed syntax is “keyword syntax”:

CALL SUB(A, B, C, IF (PRESENT(D) THEN D ELSE IF (X < 1) THEN EPSILON(X) ELSE SPACING(X) END IF)

The second proposed syntax is “? syntax”:

CALL SUB(A, B, C, ? (PRESENT(D) D :? (X < 1) EPSILON(X) : SPACING(X) ?)

I would like to encourage the wider community to leave feedback on this regrading which is more readable or what the committee should do at https://github.com/j3-fortran/fortran_proposals/issues/183

4 Likes

Ugh. Neither is more readable than the original. If J3 is pursuing the 2nd, then please adopt C’s conditional operator notation. logical-OR-expression ? expression : conditional-expression. In your second example :? seems out of place.

2 Likes

@kargl, thank you. I personally also don’t like either of the options. But I want to get as much feedback on this from the community as possible, so that I can relay the feedback to the committee. Here is the proposed syntax, I hope I translated the example correctly:

<conditional-expr> ::= (? <scalar-logical-expr> | <then-expr>
                       [ :? <scalar-logical-expr> | <elseif-expr> ]...
                       : <else-expr> ?)

<conditional-arg> ::= (? <scalar-logical-expr> | <consequent-arg>
                      [ :? <scalar-logical-expr> | <consequent-arg> ]...
                      [ : <consequent-arg> ]
                      ?)

Perhaps it is meant to look like this:

CALL SUB(A, B, C, (? (PRESENT(D)) D :? (X < 1) EPSILON(X) : SPACING(X) ?))

Now, I really prefer the original! The original is simply uncluttered. (BTW, readability is one of the reasons why journals and newspapers use narrow columns over long lines.)

Using ? to bracket the whole expression seems to be too verbose, and possibly error prone when nesting conditional expressions. If J3 adopts C’s conditional operator, then I suspect almost all Fortran compilers can easily leverage the implementation from the companion C compiler. The C operator does not have the else-if portion of the construct. One simply nests the conditional operators.

CALL SUB(A,B,C, PRESENT(D) ? D : (x < 1 ? EPSILON(X) : SPACING(x)))

I’ve used parentheses in the above for the else portion, but these are not required
as anything after a : is in the else

CALL SUB(A,B,C, PRESENT(D) ? D : x < 1 ? EPSILON(X) : SPACING(x))

If J3 does not like the possibly confusion of the re-use : can cause, then use |.

CALL SUB(A,B,C, PRESENT(D) ? D | (x < 1 ? EPSILON(X) | SPACING(x)))

The syntax is then

 <conditional-expr> ::=  <scalar-logical-expr>  ? <then-expr> | <else-expr>
2 Likes

@kargl what you write seems to be similar to this comment to try to stick to the C convention: https://github.com/j3-fortran/fortran_proposals/issues/183#issuecomment-703768480

The original form is clearer to me. People without exposure to C and little programming experience can figure out the meaning of the original code without much trouble while the C style expression needs further knowledge, and it just one more way to do the same thing. The C style expression with written keywords is just too verbose and defeats the only thing going for this which is conciseness.

I’m gonna say that although I’m not very fond of python, I do agree with the motto “Special cases aren’t special enough to break the rules” and this seems like an example of it.

4 Likes

Looking at the examples in the first post (but not other documents yet, sorry…), I almost feel the same as Steve Kargl (@kargl), i.e., both versions are not very readable :cold_sweat: In particular, ? cond ... (where the question mark appears first) seems extremely confusing. If the “?” is possibly to be used, I think the usual conditional (cond ? A : B) or the last example by @kargl above (using |) seems better to me.

Also, I remember I have seen several discussions on the net that nested conditional expressions are rather confusing (and so discouraged by some people). I guess the same concern may also apply here, e.g., in the examples in the first post.

RE keyword (if-else) vs “?”, other languages that introduced conditional expressions recently might have related discussions about pros and cons, which may be useful as a reference.

In my case, I use only a single conditional expression in one statement, like

Nsteps = ifelse( some_flag, 10**6, 100 )

in a way similar to some_flag ? 10**6 : 100, where ifelse is a CPP macro

#define ifelse(q,x,y) merge(x,y,q)

This works fine for integers etc, but does not work for character strings (e.g., ifelse( flag, "yes", "no" ) is an error because “yes” and “no” have different string lengths.

For comparison, Julia has both cond ? A : B and ifelse(), and Chapel has if (cond) then A else B. The latter seems close to the example in the first post, but without attaching endif.

1 Like

Thank you everybody for the feedback. More syntax forms are being considered:


At this point, using the C syntax, or the “arrow syntax” (same as C, but using -> instead of ?) is the most readable (from all the alternatives) that some people are actually in favor of. To be honest, I still find the “original form” the most readable, because nested conditional expressions become unreadable to me quickly.

2 Likes