@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:
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.
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.
I agree, but the original code has logic that should be within subroutine sub, not in the caller. A local variable d_ could be set appropriately. Fortran already has the ability to write call sub(a,b,c,d) even if d is not present in the caller.
IMO an unglamorous strength of Fortran is that you don’t need to be as smart to use it effectively or read it as some other programming languages, and the proposals are not in that spirit.
I feel like the use of if (present(x)) then x endif is perhaps an over-simplified use case. As you say, the called subroutine can easily handle this case itself. But this stops being true if sub is called in multiple places, with different requirements in each case. e.g. if you had something like
function even_factorial(x) result(y)
y = factorial(if (modulo(x,2)==0) then x else x+1 endif)
end function
function odd_factorial(x) result(y)
y = factorial(if (modulo(x,2)==1) then x else x-1 endif)
end function
I use a default function in my codes, similar to optval in stdlib, that accepts two arguments, the second optional, and returns the second argument if present, otherwise the first. So I’d write the code above as
Since epsilon(x) and spacing(x) do not require computation, this is fine. When the default values of an expression do require considerable computation, then the wordy if block is required to avoid redundant computation.
In general, Fortran does not have lazy evaluation. Would it be possible to have an intrinsic function, say lazy_merge(x,y,true_or_false), that breaks this pattern and for which the compiler evaluates the third argument first and then evaluates the first or second as appropriate? This would simplify a lot of code. I guess this is just different syntax from what is being proposed?
P.S. Why does the committee use all upper case in code examples?
I’m under the impression syntax along the lines of cond .then. A .else. B was brought up a while ago during verbal discussions at a subcommittee meeting but the response was the language with its base of existing processors supporting both free-form and fixed-form source forms needed a “beginning” and “ending” set of tokens and thus came about the options of inline if .. then .. end if constructs and ? .. ?, ( .. ) forms, etc…
We started a poll to collect feedback on this feature. We’ll present the results of the poll to the Committee on Monday when the proposals for this feature are due for discussion and a vote.
Compilers already have to handle cond .then. A .else. B if there are user-defined operators named .then. and .else.. They need to be able to parse this in either source form. So I don’t see what the problem would be.
IIRC, Fortran does not impose the “left-to-right” evaluation order for an expression (i.e. “terms can be evaluated in any order for maximal efficiency”), so isn’t the user-defined operators in this form not guaranteed to work as expected?
[ Edit ]
I guess attaching parentheses like (cond .then. A) .else. B may be useful, but the end result is probably the same as merge(A, B, cond), in that both A and B are evaluated?
Btw I’ve played with a ternary expression and merge() below, and the latter seems to evaluate only one of A and B for gfortran-10… (but I guess this is not guaranteed to behave the same for different compilers?)
test code
// test.cpp
#include <iostream>
using namespace std;
int f(int n) { cout << "(f called) "; return n * 10; }
int g(int n) { cout << "(g called) "; return n * 100; }
int main() {
int n;
cin >> n;
cout << ( n > 0 ? f(n) : g(n) ) << endl;
}
!! test.f90
integer function f(n); print *, "(f called) "; f = n * 10 ; end
integer function g(n); print *, "(g called) "; f = n * 100 ; end
program main
integer n, f, g, ans
read *, n
ans = merge( f(n), g(n), n > 0 )
print *, ans
end
First, there are sufficient differences in the semantics involved with conditional expressions, particularly with chaining, to make the analogy with user-defined operators inapplicable here. Secondly, the rules with the order of operations are fraught with so many practical difficulties, one has to bring in a beginning and ending token anyway for any deterministic usage, the tokens being parentheses.