Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Add a version of .and. that short-circuits?

1,128 views
Skip to first unread message

Beliavsky

unread,
May 9, 2018, 7:15:09 PM5/9/18
to
The thread "optimization: evaluating function calls in logical expressions" and my own Fortran experience make me wonder we should add a version of the .and. operator that does short-circuit. Maybe use the && syntax? It would be useful when handling optional arguments. One could write

if (present(arg) && arg > 0) ! do something

instead of

if (present(arg)) then
if (arg > 0) ! do something
end if

Phillip Helbig (undress to reply)

unread,
May 9, 2018, 8:03:21 PM5/9/18
to
In article <b511bbb0-3347-47e0...@googlegroups.com>,
Beliavsky <beli...@aol.com> writes:

> The thread "optimization: evaluating function calls in logical expressions"=
> and my own Fortran experience make me wonder we should add a version of th=
> e .and. operator that does short-circuit. Maybe use the && syntax? It would=
> be useful when handling optional arguments. One could write
>
> if (present(arg) && arg > 0) ! do something
>
> instead of=20
>
> if (present(arg)) then
> if (arg > 0) ! do something
> end if

Does anyone RELY on all expressions being evaluated? Surely the
compiler is free to stop evaluating as soon as one is false. One could
see this as a quality-of-implementation issue, or perhaps a compiler
option to a) force left-to-right evaluation and b) stop at the first
false instance (though this might inhibit other optimizations).

If a short-circuit variant is introduced, folks might think that the
traditional one is guaranteed not to short-circuit, which I don't think
is the case (and changing it to do so wouldn't be a good idea).

FortranFan

unread,
May 9, 2018, 10:16:01 PM5/9/18
to
On Wednesday, May 9, 2018 at 3:15:09 PM UTC-4, Beliavsky wrote:

> .. make me wonder we should add a version of the .and. operator that does short-circuit. Maybe use the && syntax? ..


Well, in that other thread Dan Nagle already indicated the Fortran standards committee might consider proposals to introduce.andthen. and .orelse. operators:
https://groups.google.com/d/msg/comp.lang.fortran/fXP1c0u57So/BoM2Ly55BwAJ

Nasser M. Abbasi

unread,
May 10, 2018, 12:20:17 AM5/10/18
to
Not only for .and. but also short circuit for .or.

Here is rosettacode entry. Many language support this feature
for .and. and also .or.

https://rosettacode.org/wiki/Short-circuit_evaluation

Ada uses "and then" and "or else" for these.

--Nasser

robin....@gmail.com

unread,
May 10, 2018, 1:27:22 AM5/10/18
to
IMHPOn Thursday, May 10, 2018 at 6:03:21 AM UTC+10, Phillip Helbig (undress to reply) wrote:
> In article <b511bbb0-3347-47e0...@googlegroups.com>,
> Beliavsky <bel.....@aol.com> writes:
>
> > The thread "optimization: evaluating function calls in logical expressions"=
> > and my own Fortran experience make me wonder we should add a version of th=
> > e .and. operator that does short-circuit. Maybe use the && syntax? It would=
> > be useful when handling optional arguments. One could write
> >
> > if (present(arg) && arg > 0) ! do something
> >
> > instead of=20
> >
> > if (present(arg)) then
> > if (arg > 0) ! do something
> > end if
>
> Does anyone RELY on all expressions being evaluated?

Yes, all of an expression needs to be evaluated.

> Surely the
> compiler is free to stop evaluating as soon as one is false.

Well, it could, but that may result in wrong results when
any function evaluation is skipped.
Or, it may result in some error going undetected (e.g., division by zero,
or subscript bound error) in the latter part of an expression).

> One could
> see this as a quality-of-implementation issue, or perhaps a compiler
> option to a) force left-to-right evaluation and b) stop at the first
> false instance (though this might inhibit other optimizations).

> If a short-circuit variant is introduced, folks might think that the
> traditional one is guaranteed not to short-circuit, which I don't think
> is the case (and changing it to do so wouldn't be a good idea).

IMHO changing it to do so would be a good idea.
It cannot break existing code.

Steve Lionel

unread,
May 10, 2018, 8:24:55 PM5/10/18
to
On 5/9/2018 9:27 PM, robin....@gmail.com wrote:
>> Does anyone RELY on all expressions being evaluated?
> Yes, all of an expression needs to be evaluated.

No, it doesn't:

(18-007) 10.1.7 Evaluation of operands
It is not necessary for a processor to evaluate all of the operands of
an expression, or to evaluate entirely each operand, if the value of the
expression can be determined otherwise.

--
Steve Lionel
Retired Intel Fortran developer/support
Email: firstname at firstnamelastname dot com
Twitter: @DoctorFortran
LinkedIn: https://www.linkedin.com/in/stevelionel
Blog: http://intel.com/software/DrFortran

Louis Krupp

unread,
May 10, 2018, 8:58:27 PM5/10/18
to
On Wed, 9 May 2018 12:15:07 -0700 (PDT), Beliavsky <beli...@aol.com>
wrote:

>The thread "optimization: evaluating function calls in logical expressions" and my own Fortran experience make me wonder we should add a version of the .and. operator that does short-circuit.

<snip>

For what it's worth, Unisys ALGOL (a descendant of Burroughs Extended
ALGOL) uses "CAND" ("conditional and") and "COR". My understanding is
that the logical operators "AND" and "OR" are bitwise, just like & and
&& in C, so they can't short-circuit, but CAND and COR operate only on
the low-order bit, which is what determines truth value in Unisys
ALGOL.

Louis

robin....@gmail.com

unread,
May 11, 2018, 1:34:08 AM5/11/18
to
On Friday, May 11, 2018 at 6:24:55 AM UTC+10, Steve Lionel wrote:
> On 5/9/2018 9:27 PM, r.....@gmail.com wrote:
> >> Does anyone RELY on all expressions being evaluated?
> > Yes, all of an expression needs to be evaluated.
>
> No, it doesn't:

I said that it NEEDS to be evaluated.

I know that evaluation can be skipped.
It has always been like that.

However, doing so leads to errors that can trap the unwary.
It can also lead to the same program producing different
results with different compilers.

Clive Page

unread,
May 11, 2018, 9:00:01 AM5/11/18
to
None of the previous comments on this thread seem to have dealt with this specific case. I find using optional arguments for procedures rather convenient, but the syntax for dealing with them is cumbersome.

I would strongly support Beliavsky's suggestion of a short-circuiting && operator just on the grounds that it simplifies this case. It might be useful in other contexts, of course.


--
Clive Page

Beliavsky

unread,
May 11, 2018, 11:54:56 AM5/11/18
to
On Friday, May 11, 2018 at 5:00:01 AM UTC-4, Clive Page wrote:
> On 09/05/2018 20:15, Beliavsky wrote:
> > The thread "optimization: evaluating function calls in logical expressions" and my own Fortran experience make me wonder we should add a version of the .and. operator that does short-circuit. Maybe use the && syntax? It would be useful when handling optional arguments. One could write
> >
> > if (present(arg) && arg > 0) ! do something
> >
> > instead of
> >
> > if (present(arg)) then
> > if (arg > 0) ! do something
> > end if
>
> None of the previous comments on this thread seem to have dealt with this specific case. I find using optional arguments for procedures rather convenient, but the syntax for dealing with them is cumbersome.

In the absence of short-circuiting, here is what I do now. If I have an optional logical argument debug, which if .true. means that the procedure prints some intermediate results, I can write

if (default(.false.,debug)) ! do something

where default is an interface defined in a module with module procedures default_logical, default_integer, etc. and default_logical is as follows:

elemental function default_logical(a,b) result(c)
logical, intent(in) :: a
logical, intent(in), optional :: b
logical :: c
if (present(b)) then
c = b
else
c = a
end if
end function default_logical

Stefano Zaghi

unread,
May 11, 2018, 12:23:11 PM5/11/18
to
Nice tricks!

I use a lot optional arguments...

Thanks for sharing it.

My best regards.

Dick Hendrickson

unread,
May 11, 2018, 2:25:04 PM5/11/18
to
On 5/10/18 3:24 PM, Steve Lionel wrote:
> On 5/9/2018 9:27 PM, robin....@gmail.com wrote:
>>> Does anyone RELY on all expressions being evaluated?
>> Yes, all of an expression needs to be evaluated.
>
> No, it doesn't:
>
> (18-007) 10.1.7 Evaluation of operands
> It is not necessary for a processor to evaluate all of the operands of
> an expression, or to evaluate entirely each operand, if the value of the
> expression can be determined otherwise.
>
It's the last phrase that causes one of the problems with side effects.
Given

a = F(1.0)

is the compiler >required< to evaluate F? Or can it determine the value
some other way? (Divine intervention perhaps?) Or, if F is

function F(x)
Print *, "executing F"
F = 3
end

the compiler can easily determine that F is 3 and therefore doesn't need
to "evaluate" F. So, no printing of "executing F".

Dick Hendrickson

Dominik Gronkiewicz

unread,
May 13, 2018, 1:39:28 PM5/13/18
to
Honestly, this is how OPTIONAL should be handled in the language:

subroutine opt1(a, b = 5)
integer, intent(in) :: a, b
end subroutine

subroutine opt2(a, b)
integer, intent(in) :: a
integer, intent(in), optional(5) :: b
end subroutine

in both cases, b would be an optional argument, defaulting to 5. I find having to use two sets of variables (because if optional variable is not present, you cannot assign it a value) is extremely frustrating.

Beliavsky

unread,
May 13, 2018, 3:29:28 PM5/13/18
to
Sometimes optional arguments are not scalars, and the flexible Fortran approach allows code such as this:

function dproduct(x,y,wgt) result(xy)
real, intent(in) :: x(:),y(:)
real, intent(in), optional :: wgt(:)
real :: xy
if (present(wgt)) then
xy = sum(x*y*wgt)
else
xy = sum(x*y)
end if
end function dproduct

Ron Shepard

unread,
May 13, 2018, 4:49:57 PM5/13/18
to
On 5/13/18 8:39 AM, Dominik Gronkiewicz wrote:
>
> Honestly, this is how OPTIONAL should be handled in the language:
>
> subroutine opt1(a, b = 5)
> integer, intent(in) :: a, b
> end subroutine
>
> subroutine opt2(a, b)
> integer, intent(in) :: a
> integer, intent(in), optional(5) :: b
> end subroutine
>
> in both cases, b would be an optional argument, defaulting to 5. I find having to use two sets of variables (because if optional variable is not present, you cannot assign it a value) is extremely frustrating.
>

This is a combination of allowing optional arguments in the caller and
of assigning a local replacement in the callee at the same time. That
might be useful in some cases, but not in all, perhaps not even the
majority where optional arguments are used. For example, this would
preclude the idea of passing that variable down the calling tree while
maintaining the original present() status, a very useful feature of the
current semantics.

With the current fortran semantics, you can achieve this already in two
different ways, one using a local variable,

local_b = default_value
if (present(b)) local_b = b

or a second using a local pointer,

local_b => local_object
if (present(b)) local_b => b

The best choice depends on what exactly is done with the local_b
references afterwards. Now that allocatable scalars are in the language,
this can be done efficiently also for user defined data type scalars as
well as arrays.

$.02 -Ron Shepard

Dominik Gronkiewicz

unread,
May 14, 2018, 2:00:09 AM5/14/18
to
I think the syntax that I proposed does not exclude optional arguments working in the way the are now (so no clash with current language and both given codes would compile and work as expected), but fixes a very common use case, where the programmer doesn't care whether the default or user given value is used, and which I believe covers most of the cases, while not polluting the namespace with obfuscated names such as local_x, local_b.

robin....@gmail.com

unread,
Jul 7, 2018, 2:41:32 AM7/7/18
to
On Saturday, May 12, 2018 at 12:25:04 AM UTC+10, Dick Hendrickson wrote:
> On 5/10/18 3:24 PM, Steve Lionel wrote:
> > On 5/9/2018 9:27 PM, r......@gmail.com wrote:
> >>> Does anyone RELY on all expressions being evaluated?
> >> Yes, all of an expression needs to be evaluated.
> >
> > No, it doesn't:

I said it needs to be.

> > (18-007) 10.1.7 Evaluation of operands
> > It is not necessary for a processor to evaluate all of the operands of
> > an expression, or to evaluate entirely each operand, if the value of the
> > expression can be determined otherwise.
> >
> It's the last phrase that causes one of the problems with side effects.

I think that that rule was originally intended to cover
such expressions as in
y = f(x) + f(z) - 1/f(x)
to allow the practice of some vendors to avoid evaluating
f(x) twice.
However, such avoidance has dubious benefits, including as exemplified
in the example below.

john.coll...@gmail.com

unread,
Jul 8, 2018, 9:39:13 AM7/8/18
to
This is just one of a number of situations in Fortran where the order of evaluation of sub-expressions within a statement is undefined. In statements like
CALL s(f1(i),f2(j))
where f1 and f2 are functions, different compilers may choose different orders of evaluation of the functions. This causes problems in comparative debugging, where program execution, and the LHS values computed, are captured under one compiler and compared with those computed under another - see Collins J, Farrimond B, Flower D, Anderson M and Gill D. 2013, "The Removal of Numerical Drift from Scientific Models", arXiv:1304.3260 [cs.SE]. We had to create a tool to enforce the order of computation.

If the order of computation in .AND. and .OR. constructs and in sub-program calls were required to be from left to right, and logical expressions were required to short-circuit, this would not change the meaning of any existing programs. There might be a small penalty in optimisation, but control would be returned to the programmer. Do we need a new operator, or simply a change in the specifications of logical operators and expressions?

Best wishes,

John

robin....@gmail.com

unread,
Jul 8, 2018, 11:15:42 AM7/8/18
to
On Sunday, July 8, 2018 at 7:39:13 PM UTC+10, john.coll...@gmail.com wrote:
> On Wednesday, 9 May 2018 20:15:09 UTC+1, Beliavsky wrote:
> > The thread "optimization: evaluating function calls in logical expressions" and my own Fortran experience make me wonder we should add a version of the .and. operator that does short-circuit. Maybe use the && syntax? It would be useful when handling optional arguments. One could write
> >
> > if (present(arg) && arg > 0) ! do something
> >
> > instead of
> >
> > if (present(arg)) then
> > if (arg > 0) ! do something
> > end if
>
> This is just one of a number of situations in Fortran where the order of evaluation of sub-expressions within a statement is undefined. In statements like
> CALL s(f1(i),f2(j))
> where f1 and f2 are functions, different compilers may choose different orders of evaluation of the functions. This causes problems in comparative debugging, where program execution, and the LHS values computed, are captured under one compiler and compared with those computed under another - see Collins J, Farrimond B, Flower D, Anderson M and Gill D. 2013, "The Removal of Numerical Drift from Scientific Models", arXiv:1304.3260 [cs.SE]. We had to create a tool to enforce the order of computation.
>
> If the order of computation in .AND. and .OR. constructs and in
> sub-program calls were required to be from left to right,
> and logical expressions were required to short-circuit,
> this would not change the meaning of any existing programs.

It would indeed change the meaning of programs.
The evaluation of an expression to the right of an .OR. operator
(including any function calls) would not take place once an operand
to the left of an .OR. operator had evaluated to .TRUE., for example.

Ron Shepard

unread,
Jul 8, 2018, 4:18:34 PM7/8/18
to
On 7/8/18 4:39 AM, john.coll...@gmail.com wrote:
> There might be a small penalty in optimisation, but control would be returned to the programmer.

As the example in this thread shows, the fortran programmer is already
in complete control of the situation. The only thing accomplished by the
proposed change is the saving a few characters of typing. That might be
a worthy goal, but it is only a minor one. If a new set of operators
were added to allow this, my guess is that many programmers might
continue to use explicit nested expressions to make the intent of that
sequence of comparisons more clear to future programmers. The downside
is that some inexperienced programmers might use the new operators in
situations where they were not needed, unknowingly eliminating the
possibility of the currently allowed compiler optimizations that you
mention above. In view of all of this, it is unsurprising that this has
not been introduced into the language already.

$.02 -Ron Shepard

Dominik Gronkiewicz

unread,
Jul 8, 2018, 5:48:29 PM7/8/18
to
I still cannot help but think that allowing such optimizations for non-pure function is simply a flaw of the language. If the operators work this way -- so be it. It's a great optimization tool that allows writing clear code and letting compiler do the job (isn't this the reason why we aren't all using C++?). But then, functions with side effects may cause an unexpected behavior of the code without even warning the user, which (in my opinion) is unacceptable.

john.coll...@gmail.com

unread,
Jul 8, 2018, 5:56:33 PM7/8/18
to
> >
> > If the order of computation in .AND. and .OR. constructs and in
> > sub-program calls were required to be from left to right,
> > and logical expressions were required to short-circuit,
> > this would not change the meaning of any existing programs.
>

Robin wrote:

> It would indeed change the meaning of programs.
> The evaluation of an expression to the right of an .OR. operator
> (including any function calls) would not take place once an operand
> to the left of an .OR. operator had evaluated to .TRUE., for example.
>

No, it would not. Please see Steve Lionel's post earlier in this thread. The compiler is not required to evaluate all sub-expressions once the overall result is unambiguously determined and our experiments with ifort, gfortran, CVF, Fujitsu and FTN95 confirm this. From our point of view the curse is that the behaviour is undefined. In consequence:

i. We have to re-engineer the code for comparative debugging. No longer a problem - we have automated this.

ii. Programmers may develop codes which run reliably on one system but cannot be migrated to another. We found many examples in WRF moving from ifort to Fujitsu. This is a trap in the language, and I don't think we should be setting traps.

iii. You need more pencil to write unambiguous code. Granted, this is not a big issue, but it encourages the unwary to fall into the trap.

Best wishes,

John

john.coll...@gmail.com

unread,
Jul 8, 2018, 6:08:00 PM7/8/18
to
I think the most important issue is that in the current situation the program flow is undefined. If the logical expressions contain functions with side effects, or reference objects which may not be present or may be undefined, there is a maintenance and portability trap. We have seen many experienced programmers fall into this (The community who maintain WRF generally know what they are doing).

Best wishes,

John

robin....@gmail.com

unread,
Jul 11, 2018, 5:00:05 AM7/11/18
to
On Monday, July 9, 2018 at 3:56:33 AM UTC+10, john.coll...@gmail.com wrote:

>>John Coll wrote:

>> > If the order of computation in .AND. and .OR. constructs and in
>> > sub-program calls were required to be from left to right,
>> > and logical expressions were required to short-circuit,
>> > this would not change the meaning of any existing programs.

>Robin replied:

>> It would indeed change the meaning of programs.
>> The evaluation of an expression to the right of an .OR. operator
>> (including any function calls) would not take place once an operand
>> to the left of an .OR. operator had evaluated to .TRUE., for example.

> No, it would not. Please see Steve Lionel's post earlier in this thread.

I'm aware of what he wrote, as I had to correct his
mis-interpretation of what I posted.

And yes it would. At present, a processor is not REQUIRED
to evaluate all of an expression. But it MAY and CAN.
Hence what you wrote would change the meaning of programs
(if it became a rule).

> The compiler is not required to evaluate all sub-expressions
> once the overall result is unambiguously determined

I'm aware of that.
As I said above, the compiler is not REQUIRED to evaluate all
sub-expressions, but it MAY and CAN do so.

Therefore what you suggested WOULD alter the meaning of programs.

> and our experiments with ifort, gfortran, CVF, Fujitsu and FTN95 confirm this.

That's only a small number of compilers that are around.
But what did you "confirm"? (FTN95 does not short-circuit).

> From our point of view the curse is that the behaviour is undefined.

That's why I wrote that such expressions need to be fully evaluated.

If one compiler can fully evaluate an expression and another does not,
there are inconsistencies in the interpretation of the intent of the program.
There may even be differences depending on whether a particular compiler
is in fast compilation mode and in optimising mode.

Most people would not be aware of the inconsistency,
and write their programs accordingly, assuming that
expressions are fully evaluated.

> In consequence:

> i. We have to re-engineer the code for comparative debugging. No longer a problem -
> we have automated this.

> ii. Programmers may develop codes which run reliably on one system but cannot be migrated to another.
> We found many examples in WRF moving from ifort to Fujitsu. This is a trap in the language,
> and I don't think we should be setting traps.

> iii. You need more pencil to write unambiguous code. Granted, this is not a big issue,
> but it encourages the unwary to fall into the trap.

So, are you going to modify all your programs that perform
arithmetic? since evaluating the expression a * (e/f) can avoid
computing e/f when the value of a is zero.

Dominik Gronkiewicz

unread,
Jul 11, 2018, 12:18:47 PM7/11/18
to
Another option is to make all functions PURE by default, and for backwards compatibility, add "impure" keyword to mark functions with side-effects. I imagine that merely a thought of writing an "impure function" would encourage programmers to look for another solution. :-D

Gary Scott

unread,
Jul 11, 2018, 1:37:45 PM7/11/18
to
that would not be consistent with the common definition of backwards
compatibility. That would require no change in behavior when the
keyword is NOT present, and so would require the keyword to be "pure".

Ev. Drikos

unread,
Jul 11, 2018, 2:59:05 PM7/11/18
to
On 11/07/2018 15:18, Dominik Gronkiewicz wrote:
> Another option is to make all functions PURE by default, and for backwards compatibility, add "impure" keyword to mark functions with side-effects.


Hello,

To my understanding, the term "backwards compatibility" means that
existing code will continue to compile & work as it did before.

If you have to add the keyword "impure" to a function with a print
statement then the recommended change doesn't provide backwards
compatibility but exactly the opposite


PS: maybe I've missed some joke here :-)

JCampbell

unread,
Jul 12, 2018, 2:14:50 AM7/12/18
to
"backwards compatibility" for standard conforming code.
You won't find much of that in legacy code.

Dominik Gronkiewicz

unread,
Jul 12, 2018, 2:59:45 AM7/12/18
to
> To my understanding, the term "backwards compatibility" means that
> existing code will continue to compile & work as it did before.
>
> If you have to add the keyword "impure" to a function with a print
> statement then the recommended change doesn't provide backwards
> compatibility but exactly the opposite

Depends on how you understand it. I believe that good approach to backwards compatibility is to "give programmers a possibility to temporarily use old behavior" rather than "leave things broken and just add new things on top of it to confuse the users". Fixing broken design will inevitably lead to making something not compile anymore, the question is how to do it at minimal cost and pain. Please notice that well-written code (that contains only side effects free functions) would still compile without a single change (or very minor ones), and other codes would need to be revised (which is also a good thing as it would probably reveal a ton of bugs).

If non-pure functions invoke undefined behavior in the current expression evaluation rules, they should either (1) not exist (which means all functions must be pure, or at least have some limitations on what is allowed within function body), (2) expression evaluation should be changed to predictable or (3) Fortran remains inconsistent in this matter. I am not arguing that what I proposed is the best way to fix this issue, but undoubtedly something is stinking here, and it must be resolved at some point.

Ev. Drikos

unread,
Jul 12, 2018, 10:18:45 AM7/12/18
to
On 12/07/2018 05:14, JCampbell wrote:
> ...
>
> "backwards compatibility" for standard conforming code.

Yes, my comment applies mainly to standard conforming code.

> You won't find much of that in legacy code.
>

Regards,
Ev. Drikos

john.coll...@gmail.com

unread,
Jul 12, 2018, 4:37:47 PM7/12/18
to
One of Ev Drikos' posts lead me to re-examine the behaviour of different compilers in short-circuiting logical expressions. In the program:

MODULE m
LOGICAL :: l1,l2
CONTAINS
SUBROUTINE set_conditions
WRITE(*,'("l1: ",$)')
READ(*,'(L1)')l1
WRITE(*,'("l2: ",$)')
READ(*,'(L2)')l2
END SUBROUTINE set_conditions
END MODULE m

PROGRAM t
USE m
LOGICAL,EXTERNAL :: f1,f2

CALL set_conditions

IF (f1() .AND. f2()) THEN
WRITE(*,'("Condition .TRUE.")')
ELSE
WRITE(*,'("Condition .FALSE.")')
ENDIF

END PROGRAM t ! *********************************************************

LOGICAL FUNCTION f1()
USE m
WRITE(*,'("f1 was called")')
f1 = l1
END FUNCTION f1

LOGICAL FUNCTION f2()
USE m
WRITE(*,'("f2 was called")')
f2 = l2
END FUNCTION f2

with the inputs for l1 and l2 both false, I found that the program calls:

CVF f1 only
FTN95 f1 and f2
G95 f1 only
gfortran 7.1.0 f1 only
gfortran 8.0.1 f1 only
ifort f1 and f2
Oracle developer Studio f1 only
pgfortran f1 only

Now I believe that the logical expression is standard-conforming (Sorry about the $ edit descriptor). The code is ambiguous. I feel that the language should not be ambiguous. For that reason I suggest that the language should be changed.

(Before anyone asks, the compiler versions used were:
CVF 6.6.C
FTN95 4.9.0
G95 (GCC 4.0.3 (g95 0.94!) Jan 17 2013)
GNU Fortran (Ubuntu 7.1.0-10ubuntu1~16.04.york0) 7.1.0
GNU Fortran (Ubuntu 8-20180414-1ubuntu2) 8.0.1 20180414 (experimental) [trunk revision 259383]
ifort (IFORT) 16.0.1 20151021
Oracle developer Studio 12.6
pgfortran 18.4-0 64-bit Linux -tp haswell )

Best wishes,

John

Ev. Drikos

unread,
Jul 12, 2018, 5:21:01 PM7/12/18
to
On 08/07/2018 12:39, john.coll...@gmail.com wrote:
> ...
> Do we need a new operator, or simply a change in the specifications
> of logical operators and expressions?
> Best wishes,
>
> John
>

Hello,

IMHO, duplicate operators just for short-circuiting would be redundant.
Of course, my subjective opinion might be completely flawed.

An alternative approach could be an extension to the specification-part,
before or after a use-stmt, which would allow such a setting at the
program unit level:

<short-circuiting> ::=
FORCE SHORT CIRCUITING

Some compilers already support compilation (switch) options that have
this effect (likely more options if I remember correctly) whereas other
compilers (ie gfortran) provide by default that program behavior.

Last but not least, such a compilation (switch) option that guarantees
that behavior would likely be ok also. This perhaps requires a feature
request from each Fortran implementer separately. Whereas, the Fortran
programmers would have the extra burden to use a perhaps different
option string for each compiler.


Regards,
Ev. Drikos

FortranFan

unread,
Jul 12, 2018, 5:57:23 PM7/12/18
to
On Thursday, July 12, 2018 at 12:37:47 PM UTC-4, john.coll...@gmail.com wrote:

> ..
> Now I believe that the logical expression is standard-conforming (Sorry about the $ edit descriptor). The code is ambiguous. I feel that the language should not be ambiguous. For that reason I suggest that the language should be changed...

@john.coll...@gmail.com,

The language standard for Fortran is *NOT AMBIGUOUS*, rather in section 7.1.7 Evaluation of Operands (document 10-007r1 toward Fortran 2008, current standard) it makes things clear, for example in paragraph 1:

"It is not necessary for a processor to evaluate all of the operands of an expression, or to evaluate entirely each operand, if the value of the expression can be determined otherwise."

and further illustrated in Note 7.28 in the same section of the document.

No change in the language is called for in the context of this thread, especially in connection with the example you posted.

john.coll...@gmail.com

unread,
Jul 12, 2018, 10:32:25 PM7/12/18
to
I agree: 'The language standard for Fortran is *NOT AMBIGUOUS"', However, the language is ambiguous. The same statement is permitted to have two or more interpretations under different processors. That is ambiguity. Is that what we want?

Best wishes,

John

FortranFan

unread,
Jul 13, 2018, 2:01:39 AM7/13/18
to
On Thursday, July 12, 2018 at 6:32:25 PM UTC-4, john.coll...@gmail.com wrote:

> .. the language is ambiguous. The same statement is permitted to have two or more interpretations under different processors. That is ambiguity. ..


@John,

In the context of the example you posted, your assessment about language ambiguity is incorrect. In that example, the relevant statement is

--- begin code snippet ---

IF (f1() .AND. f2()) THEN

--- end code snippet ---

and the processors you tested have all computed it correctly. However you are trying to impose a requirement the processors all present the same *side effects* (which is what your WRITE statements constitute) while arriving at their correct evaluation of the binary operand, .AND. That is baseless. There has never been that suggestion in the language that this will be the case, at least from what I can tell from way back in the day with the first IBM Fortran manual (circa 1957) through FORTRAN 66, 77 to the language as it stands now. I fail to see any ambiguity here.

Thomas Koenig

unread,
Jul 13, 2018, 5:37:09 AM7/13/18
to
john.coll...@gmail.com <john.coll...@gmail.com> schrieb:

> I agree: 'The language standard for Fortran is *NOT AMBIGUOUS"',
> However, the language is ambiguous. The same statement is permitted
> to have two or more interpretations under different processors.
> That is ambiguity. Is that what we want?

Please skim the Fortran standard.

Every time you find the word "shall" outside of a constraint
(the ones numbered "C"), the standard imposes no requirement om
what happens if the condition is violated. Each an every time
a programmer does something like that, there is total ambiguity
(you know the old adage about starting WWIII, I assume).

If you're familiar with C, the term used there is "undefined behavior".

People could try to "fix" this, but it would not be Fortran anymore,
and I certainly would give up trying to implement such a language.

Ron Shepard

unread,
Jul 13, 2018, 5:47:46 AM7/13/18
to
On 7/12/18 11:37 AM, john.coll...@gmail.com wrote:
> IF (f1() .AND. f2()) THEN
> WRITE(*,'("Condition .TRUE.")')
> ELSE
> WRITE(*,'("Condition .FALSE.")')
> ENDIF
[...]>
> with the inputs for l1 and l2 both false, I found that the program calls:
>
> CVF f1 only
> FTN95 f1 and f2
> G95 f1 only
> gfortran 7.1.0 f1 only
> gfortran 8.0.1 f1 only
> ifort f1 and f2
> Oracle developer Studio f1 only
> pgfortran f1 only

Isn't it interesting that none of the compilers evaluate only f2()?
What happens if you were to add a statement

Q2 = f2()

before the test, and then use Q2 in the logical expression? Would that
be enough to get some compilers to evaluate only f2()?

>
> Now I believe that the logical expression is standard-conforming (Sorry about the $ edit descriptor). The code is ambiguous. I feel that the language should not be ambiguous. For that reason I suggest that the language should be changed.

If you want the code to be evaluated in a particular way, then write it
that way.

if ( f1() ) then
if (f2()) then
...

or

if (f2()) then
if (f1()) then
...

The same kind of argument goes for arithmetic expressions. You do not
have to allow the compiler to decide how they are evaluated; if it is
important, then you can use parentheses or break up the expression in
multiple statements to force evaluation in a specific way.

$.02 -Ron Shepard


Phillip Helbig (undress to reply)

unread,
Jul 13, 2018, 6:25:57 AM7/13/18
to
In article <42X1D.352927$6C5.3...@fx07.iad>, Ron Shepard
<nos...@nowhere.org> writes:

> If you want the code to be evaluated in a particular way, then write it
> that way.
>
> if ( f1() ) then
> if (f2()) then
> ...
>
> or
>
> if (f2()) then
> if (f1()) then
> ...

Would one have to turn of optimization to make sure that this happens?

> The same kind of argument goes for arithmetic expressions. You do not
> have to allow the compiler to decide how they are evaluated; if it is
> important, then you can use parentheses or break up the expression in
> multiple statements to force evaluation in a specific way.

I think that this is documented whatever the optimization.

robin....@gmail.com

unread,
Jul 13, 2018, 9:22:32 AM7/13/18
to
On Friday, July 13, 2018 at 3:47:46 PM UTC+10, Ron Shepard wrote:

> If you want the code to be evaluated in a particular way, then write it
> that way.
>
> if ( f1() ) then
> if (f2()) then
> ...
>
> or
>
> if (f2()) then
> if (f1()) then
> ...
>
> The same kind of argument goes for arithmetic expressions. You do not
> have to allow the compiler to decide how they are evaluated; if it is
> important, then you can use parentheses or break up the expression in
> multiple statements to force evaluation in a specific way.

You may find that the compiler can still do the computation
in a different way when in optimising mode.

Phillip Helbig (undress to reply)

unread,
Jul 13, 2018, 9:34:08 AM7/13/18
to
In article <d31a2894-32fa-4cde...@googlegroups.com>,
Does this apply to the nested IF constructs, to forcing evaluation via
parentheses, or both?

robin....@gmail.com

unread,
Jul 13, 2018, 10:31:19 AM7/13/18
to
On Friday, July 13, 2018 at 7:34:08 PM UTC+10, Phillip Helbig (undress to reply) wrote:
> In article <d31a2894-32fa-4cde...@googlegroups.com>,
I was referring to the paragraph just above relating to the evaluation of
expressions. Even if split to separate statements, the optimiser may
carry out the operations in a different order. Moving common sub-expressions
is a common optimisation.

spectrum

unread,
Jul 13, 2018, 11:47:36 AM7/13/18
to
I remember to have read that this "ambiguity" is intentionally left for compilers
as "freedom" for making further optimization (e.g., by evaluating costly functions
later, etc). But in the above case, isn't the result by ifort and FTN95 something like
"anti-optimization"? (= more costly than the short-circuit evaluation).

Indeed, is it practically possible to evaluate the cost of functions with side effects
by compilers (given that those routines could call further deeper routines with
varying costs and implicit interfaces)? So, I'm not sure to what extent the above argument
of "leave room for optimization" is really significant (= effective), in practice...

# Btw, I imagine that the above ifort's evaluation might be to take care of users' (wrong)
expectation that both f1 and f2 are always evaluated, or to choose the "safest" side
for functions with side effects (but I feel it is also ill-defined unless the order of function
evaluation is uniquely prescribed).

spectrum

unread,
Jul 13, 2018, 12:40:45 PM7/13/18
to
FWIW, the "short-circuit evaluation" page in Rosetta Code is a bit interesting
(I'm sorry if this has already been posted above somewhere...)

https://rosettacode.org/wiki/Short-circuit_evaluation

There seem to be mainly 3 classes (<-- classification may be wrong..):

1) Provides builtin && and || with short-circuit.
AWK, ALGOL W, C etc, Java, D, Delphi (can be turned off with compiler directive)
Go, JavaScript, Julia, Kotlin, Lua, Maple, Mathematica, Matlab, Nim, Octave, OCaml
TurboPascal (w/ compiler switch), Perl, PureBasic, Python, R, Ruby, Rust, Scala, Swift
Tcl, bash, csh

2) Provides additional keywords ("andthen", "orelse", etc) for short-circuit.
Ada (and then, or else), FreeBasic (AndAlso, OrElse),
Extended Pascal (and_then, or_else), Simula (and then, or else)

3) Does not provide short-circuit, or no rule, or evaluate both always
Fortran (as of 2018), LibertyBasic, Pascal, Stata (evaluate both)

4) ...?
ALGOL 68 (with extension?), Modula-2, PL/I (similar to Fortran?)

spectrum

unread,
Jul 13, 2018, 1:04:07 PM7/13/18
to
Among these, I guess the Pascal family has the most wide variation
in their behavior (including compiler switch/directives), so I guess
maybe confusing...

[ Standard Pascal ]
Standard Pascal doesn't have native short-circuit evaluation.

[ Turbo Pascal ]
Turbo Pascal allows short circuit evaluation with a compiler switch.

[ Extended Pascal ]
The extended Pascal standard introduces the operators and_then and or_else
for short-circuit evaluation.

[ Delphi ]
Delphi supports short circuit evaluation by default. It can be turned of
using the {$BOOLEVAL OFF} compiler directive (hmm)

Gary Scott

unread,
Jul 13, 2018, 3:21:50 PM7/13/18
to
I typically code "as-if" left to right evaluation and sometimes will
have something like:

if (svEnableEvaluation .and. f()) ...

And hope that it stops at evaluating svEnableEvaluation logical if .false.

But I know that doesn't necessarily happen.

Gary Scott

unread,
Jul 13, 2018, 4:35:13 PM7/13/18
to
I have however at times decided to measure performance and altered this
flow to ensure the fastest measured path...resulting in very significant
performance improvements (e.g. much faster stacked area chart refresh
performance).

Ev. Drikos

unread,
Jul 13, 2018, 5:49:39 PM7/13/18
to
On 12/07/2018 19:37, john.coll...@gmail.com wrote:
> ...
>
> CVF f1 only
> FTN95 f1 and f2
> G95 f1 only
> gfortran 7.1.0 f1 only
> gfortran 8.0.1 f1 only
> ifort f1 and f2
> Oracle developer Studio f1 only
> pgfortran f1 only
>
> Now I believe that the logical expression is standard-conforming (Sorry about the $ edit descriptor). The code is ambiguous...
>

Thank you for sharing with us these results.

Regards,
Ev. Drikos




john.coll...@gmail.com

unread,
Jul 16, 2018, 10:13:47 AM7/16/18
to
It doesn't necessarily happen, but it usually happens, and we have seen many instances. For example:

This code was present in WRFV3.3.1

WRFV3/external/esmf_time_f90/ESMF_Base.F90 line 541

if((.not. present(namespace)) .or. (namespace .eq. "")) then
ournamespace = "global"
else
ournamespace = namespace
endif


It compiled and ran on:

IBM SP systems, (e.g. NCAR "bluevista","blueice","bluefire" Power5-based system)
IBM Blue Gene
SGI Origin and Altix
Linux/Intel
IA64 MPP (HP Superdome, SGI Altix, NCSA Teragrid systems)
IA64 SMP
x86_64 (e.g. TACC's "Ranger", NOAA/GSD "wJet" )
PGI, Intel, Pathscale, gfortran, g95 compilers supported
Sun Solaris (single threaded and SMP)
Cray X1, X1e (vector), XT3/4 (Opteron)
Mac Intel/ppc, PGI/ifort/g95
NEC SX/8
HP-UX
Fujitsu VPP 5000

It had to be changed for the Fujitsu FX compiler and the WRF code was revised in or before WRFV3.6.1

It looks as if almost all compilers use a left-to-right ordering in evaluating logical expressions, which is what the OP is looking for. Why not mandate it?

Best wishes,

John

john.coll...@gmail.com

unread,
Jul 16, 2018, 10:34:32 AM7/16/18
to
On Thursday, 12 July 2018 18:57:23 UTC+1, FortranFan wrote:
I think it could be argued that the 'value' of an expression includes its side effects. If that is accepted, then, in the example I posted above, ifort and FTN95, which compute all of the side effects, are correct and the other systems tested are incorrect. If the value of a function does not include its side effects then all functions would be handled as if they were pure.

Note also that the standard does not specify the order in which two or more functions in a single statement are executed. To carry out comparative debugging for compiler validation we had to build a tool to re-engineer code to enforce a unique order of evaluation. Would it be appropriate for the order of function evaluation to be specified in the standard?

Best wishes,

John

FortranFan

unread,
Jul 16, 2018, 1:23:24 PM7/16/18
to
On Monday, July 16, 2018 at 6:34:32 AM UTC-4, john.coll...@gmail.com wrote:

> ..
> I think it could be argued that the 'value' of an expression includes its side effects. If that is accepted, then, in the example I posted above, ifort and FTN95, which compute all of the side effects, are correct and the other systems tested are incorrect. If the value of a function does not include its side effects then all functions would be handled as if they were pure.
>


I don't think with the example code you posted, any such argument involving side effects has any merit. Also, any processor comparisons in terms of the side effects you have included in that code are meaningless. As I mentioned earlier, about the only thing that can be compared in that example is the evaluation of that 'F1() .AND. F2()' expression evaluation which is the same by all the processors you tested.


> ..Would it be appropriate for the order of function evaluation to be specified in the standard?

*NO* changes with respect to this aspect of the order of function evaluation appear necessary in the Fortran standard. The standard appears clear enough, though there is the use of the term "shall" which places responsibility on coders that is perfectly alright in my opinion.

For example, in sections such as 7.1.4 Evaluation of operations in 10-007r1 document toward Fortran 2008, "The evaluation of a function reference shall neither affect nor be affected by the evaluation of any other entity within the statement. If a function reference causes de finition or unde finition of an actual argument of the function, that argument or any associated entities shall not appear elsewhere in the same statement." and in notes such as 7.12, it says the coder is prohibited from statements such as

Y = G(X) + X ! where G can define or undefine X.

FortranFan

unread,
Jul 16, 2018, 1:30:11 PM7/16/18
to
On Monday, July 16, 2018 at 6:13:47 AM UTC-4, john.coll...@gmail.com wrote:

> ..
> This code was present in WRFV3.3.1
>
> WRFV3/external/esmf_time_f90/ESMF_Base.F90 line 541
>
> if((.not. present(namespace)) .or. (namespace .eq. "")) then
> ournamespace = "global"
> else
..
>
> It had to be changed for the Fujitsu FX compiler and the WRF code was revised in or before WRFV3.6.1
>
> It looks as if almost all compilers use a left-to-right ordering in evaluating logical expressions, which is what the OP is looking for. Why not mandate it?
> ..


I think because there will be "side effects" from such a change in the language! You can look on this forum and elsewhere and likely find discussions going back a decade or more as to why there are people who would "vote against" such a mandate.

So a proposal that pops up (there is one on the table now with Fortran 202X) is to introduce .orelse. operator to support such a coding need:

if ((.not. present(namespace)) .orelse. (namespace .eq. "")) then

john.coll...@gmail.com

unread,
Jul 16, 2018, 3:29:16 PM7/16/18
to
The requirement "The evaluation of a function reference shall neither affect nor be affected by the evaluation of any other entity within the statement... " is an appropriate ambition, but presents a very serious maintenance trap. If something deep in the call chain from one function changes something in a module which affects the behaviour of another function, the results will depend on the order of execution of the functions. At present, this is undefined. With the tools available to most users, portability issues from this will be extremely hard to find. Is it reasonable to place the responsibility to solve these problems on the user when they can be dealt with by a small change in the language?

There would be side effects of the change. Programs which at present rely on an undefined behaviour would behave differently. But are those programs correct in the first place?

Best wishes,

John


FortranFan

unread,
Jul 16, 2018, 6:54:06 PM7/16/18
to
On Monday, July 16, 2018 at 11:29:16 AM UTC-4, john.coll...@gmail.com wrote:

> .. If something deep in the call chain from one function changes something in a module which affects the behaviour of another function, the results will depend on the order of execution of the functions. At present, this is undefined. With the tools available to most users, portability issues from this will be extremely hard to find. Is it reasonable to place the responsibility to solve these problems on the user when they can be dealt with by a small change in the language?
> ..

You ask, "Is it reasonable to place the responsibility to solve these problems on the user" - my opinion is YES, ABSOLUTELY.

It's actually good business too, it can lead to commercial opportunities for those like you who can create valuable code refactoring and optimization tools for those worried about the maintenance traps you mention!

john.coll...@gmail.com

unread,
Jul 18, 2018, 12:03:01 PM7/18/18
to
On Monday, 16 July 2018 19:54:06 UTC+1, FortranFan wrote:
> On Monday, July 16, 2018 at 11:29:16 AM UTC-4, john.coll...@gmail.com wrote:
>
> > .. If something deep in the call chain from one function changes something in a module which affects the behaviour of another function, the results will depend on the order of execution of the functions. At present, this is undefined. With the tools available to most users, portability issues from this will be extremely hard to find. Is it reasonable to place the responsibility to solve these problems on the user when they can be dealt with by a small change in the language?
> > ..
>
> You ask, "Is it reasonable to place the responsibility to solve these problems on the user" - my opinion is YES, ABSOLUTELY.
>

I surrender. We can make a tool to catch this issue relatively easily. We already know:

i. All of the side effects of every function

ii. All of the inputs.

The analyses take into account the argument lists and shared data in MODULE, COMMON and EQUIVALENCE (Yes, people do still use COMMON and EQUIVALENCE). All we have to do is to identify all of the functions which occur in the same statements where the order of execution is undefined, and put the information together. I need to check for the situation where local variables may be saved in sub-programs which are called by both functions. I'm not sure that we analyse that yet.

How much interest would there be in this analysis?

Best wishes,

John

robin....@gmail.com

unread,
Jul 19, 2018, 4:56:05 AM7/19/18
to
On Monday, July 16, 2018 at 8:13:47 PM UTC+10, john.coll...@gmail.com wrote:

> Other recipients:
> It doesn't necessarily happen, but it usually happens, and we have seen many instances.
> For example: This code was present in WRFV3.3.1 WRFV3/external/esmf_time_f90/ESMF_Base.F90
> line 541 if((.not. present(namespace)) .or. (namespace
> - show quoted text -
On no-optimise option or optimise option?

> It had to be changed for the Fujitsu FX compiler

because the code was incorrect.

> and the WRF code was revised in or before WRFV3.6.1

> It looks as if almost all compilers use a left-to-right ordering

And let's not forget ifort and FTN95,
and all compilers prior to and including FORTRAN 77
that evaluated the whole expression

> in evaluating logical expressions, which is what the OP is looking for. Why not mandate it?

Definitely not.
If anything needs mandating, it's compulsory evaluation, not optionally skipping
evaluation.

It's been part of the definition since at least FORTRAN 77,
which also states that the "rule" applies to other kinds of
expressions, not just logical.

The best way to fix this is to make it compulsory to evaluate
all of the expression.

There used to be a term for ths sort of optimisation (where part
of the computation is avoided): "unsafe optimisation".

Dominik Gronkiewicz

unread,
Jul 24, 2018, 6:14:24 PM7/24/18
to
Having read some of the messages in this thread that defend the language ambiguity and leaving the responsibility on the users, rather than just keeping the rules simple and predictable, I have trouble understanding the fear from change for better.

If the standard was consistent, this code would never compile, because either functions with side effects would not be allowed (this is the job of subroutines), or function evaluation would be predictable (as in C/C++). But then old good "that would not be Fortran anymore" argument comes up because "it worked like that since FORTRAN compiler for mechanical calculator in 1932 so we should not change it". What is the Fortran way anyway? I see the Fortran philosophy as "code clear, compute fast, save time on debugging". If this philosophy will kill some old unmaintained code -- so be it, programming language is not a museum and nobody should cry. However, some seem to favor another philosophy: "keep the language broken and allow sh*tty programming habits because it worked 40 years ago and I don't want to learn proper modern programming". I cannot disagree enough with this approach. Standard should never allow dubious code to exist and compile. Nobody likes the change (nor do I), but the role of the standard is to gently encourage users to adapt by deleting bad features. Fortran with its declining popularity, slow development and tiny amount of available libraries (as compared to C/C++ or Python) has little chance of survival if it doesn't win new programmers with other features, such as ease, clarity, flexibility for optimizations and preventing errors.

I think there's no doubt Fortran is way behind its competitors in many ways, and its good sides can barely make up for it. I am afraid if the mindset doesn't change, it will stay behind for a long time, before its ultimate death.

robin....@gmail.com

unread,
Jul 25, 2018, 3:37:47 AM7/25/18
to
On Wednesday, July 25, 2018 at 4:14:24 AM UTC+10, Dominik Gronkiewicz wrote:
> Having read some of the messages in this thread that defend the language ambiguity and leaving the responsibility on the users, rather than just keeping the rules simple and predictable, I have trouble understanding the fear from change for better.
>
> If the standard was consistent, this code would never compile, because either functions with side effects would not be allowed (this is the job of subroutines), or function evaluation would be predictable (as in C/C++).

The current standard permits "unsafe" optimisations, because
the execution of legimate code can be avoided.
This is the outcome of adapting the standard to suit some compiler
vendors.

In the orignal case cited, the error could not be determined at compilation,
but would be "discovered" upon execution.

I'm happy with such optimisations as moving unvariant code outside a loop;
and of computing repeated sub-expressions only once; and of unrolling loops.
These generally don't affect results, but optionally avoiding certain
computations is not the way for robust code.

Ron Shepard

unread,
Jul 25, 2018, 7:10:21 AM7/25/18
to
On 7/24/18 1:14 PM, Dominik Gronkiewicz wrote:
> Having read some of the messages in this thread that defend the language ambiguity and leaving the responsibility on the users, rather than just keeping the rules simple and predictable, I have trouble understanding the fear from change for better.

I have trouble understanding your trouble. Several people have explained
fairly clearly their opinions. You can agree or disagree, but I don't
understand your point.

> If the standard was consistent, this code would never compile, because either functions with side effects would not be allowed (this is the job of subroutines), or function evaluation would be predictable (as in C/C++).

If you want expressions with multiple function calls to short circuit,
then you can write the code that way (with nested loops). If you want
those expressions to always evaluate all function references, then you
can write the code that way (separate statements). And if you want to
let the compiler have a chance to optimize away as much as it can, then
you can write the code that way.

> But then old good "that would not be Fortran anymore" argument comes up because "it worked like that since FORTRAN compiler for mechanical calculator in 1932 so we should not change it". What is the Fortran way anyway? I see the Fortran philosophy as "code clear, compute fast, save time on debugging".

And backwards compatibility. Few other languages can compile code from
five decades ago with modern compilers and modern language standards.

> If this philosophy will kill some old unmaintained code -- so be it, programming language is not a museum and nobody should cry.

That is your opinion. Others have different opinions on this.

> However, some seem to favor another philosophy: "keep the language broken and allow sh*tty programming habits because it worked 40 years ago and I don't want to learn proper modern programming". I cannot disagree enough with this approach. Standard should never allow dubious code to exist and compile. Nobody likes the change (nor do I), but the role of the standard is to gently encourage users to adapt by deleting bad features. Fortran with its declining popularity, slow development and tiny amount of available libraries (as compared to C/C++ or Python) has little chance of survival if it doesn't win new programmers with other features, such as ease, clarity, flexibility for optimizations and preventing errors.

Generally the fortran approach is to introduce new features to the
language that allow various advantages, while maintaining as much as
possible backward compatibility.

> I think there's no doubt Fortran is way behind its competitors in many ways,

And there is no doubt that it is ahead of its competitors in many ways
too. For a simple example, one could specify lower and upper bounds in
arrays in f77. I use that feature daily, almost every time I write a
fortran code. Many other languages still do not allow that, and that
feature is from 40 years ago.

> and its good sides can barely make up for it. I am afraid if the mindset doesn't change, it will stay behind for a long time, before its ultimate death.

I also worry about the survival of the language, but my opinion about
its problems are different from yours.

1) It should be easy to read and write spreadsheet files. This should
have been done in the 80s when visicalc and excel and other spreadsheets
became popular. Maybe this should be extended to database access too.

2) There should be a bit data type that allows arbitrary strings of bits
to be processed. This should have been done in the 80s when image
processing and computer typesetting became popular.

3) It should be easy to plot graphs to a screen. This should have been
done in the 80s when MacOS, Xwindows, and other graphical interfaces
became popular.

4) It should be easy to display 3D animations (molecules reacting, fluid
flow, galaxies colliding, virtual reality, etc.). This should have been
done in the 90s.

5) It should be easy to read an array of unknown length. This should
have been added to the language when allocatable arrays were introduced
in f90.

6) It should be easy to query to see the amount of memory allocated, and
when appropriate, the amount of memory available for future allocations.
This should have been a feature of f90 when allocatable and automatic
arrays were introduced to the language.

Those are some items off the top of my head. I'm sure I could think of a
few more with a little effort.

$.02 -Ron Shepard

robin....@gmail.com

unread,
Jul 25, 2018, 9:02:19 AM7/25/18
to
On Wednesday, July 25, 2018 at 5:10:21 PM UTC+10, Ron Shepard wrote:
> On 7/24/18 1:14 PM, Dominik Gronkiewicz wrote:
> > Having read some of the messages in this thread that defend the language ambiguity and leaving the responsibility on the users, rather than just keeping the rules simple and predictable, I have trouble understanding the fear from change for better.
>
> I have trouble understanding your trouble. Several people have explained
> fairly clearly their opinions. You can agree or disagree, but I don't
> understand your point.
>
> > If the standard was consistent, this code would never compile, because either functions with side effects would not be allowed (this is the job of subroutines), or function evaluation would be predictable (as in C/C++).
>
> If you want expressions with multiple function calls to short circuit,
> then you can write the code that way (with nested loops). If you want
> those expressions to always evaluate all function references, then you
> can write the code that way (separate statements). And if you want to
> let the compiler have a chance to optimize away as much as it can, then
> you can write the code that way.

The point is that if you write

"if (present(arg) && arg > 0) ! do something "

This may run "OK" at execution time, or it may crash,
depending on whether the compiler partially or fully evaluates
the expression.

It may also depend on the level of optimisation specified.

> > But then old good "that would not be Fortran anymore" argument comes up because "it worked like that since FORTRAN compiler for mechanical calculator in 1932 so we should not change it". What is the Fortran way anyway? I see the Fortran philosophy as "code clear, compute fast, save time on debugging".
>
> And backwards compatibility. Few other languages can compile code from
> five decades ago with modern compilers and modern language standards.

PL/I can.

> > If this philosophy will kill some old unmaintained code -- so be it, programming language is not a museum and nobody should cry.
>
> That is your opinion. Others have different opinions on this.
>
> > However, some seem to favor another philosophy: "keep the language broken and allow sh*tty programming habits because it worked 40 years ago and I don't want to learn proper modern programming". I cannot disagree enough with this approach. Standard should never allow dubious code to exist and compile. Nobody likes the change (nor do I), but the role of the standard is to gently encourage users to adapt by deleting bad features. Fortran with its declining popularity, slow development and tiny amount of available libraries (as compared to C/C++ or Python) has little chance of survival if it doesn't win new programmers with other features, such as ease, clarity, flexibility for optimizations and preventing errors.
>
> Generally the fortran approach is to introduce new features to the
> language that allow various advantages, while maintaining as much as
> possible backward compatibility.
>
> > I think there's no doubt Fortran is way behind its competitors in many ways,
>
> And there is no doubt that it is ahead of its competitors in many ways
> too. For a simple example, one could specify lower and upper bounds in
> arrays in f77.

That has been possible in PL/I since 1966.

> I use that feature daily, almost every time I write a
> fortran code. Many other languages still do not allow that, and that
> feature is from 40 years ago.
>
> > and its good sides can barely make up for it. I am afraid if the mindset doesn't change, it will stay behind for a long time, before its ultimate death.
>
> I also worry about the survival of the language, but my opinion about
> its problems are different from yours.
>
> 1) It should be easy to read and write spreadsheet files. This should
> have been done in the 80s when visicalc and excel and other spreadsheets
> became popular. Maybe this should be extended to database access too.
>
> 2) There should be a bit data type that allows arbitrary strings of bits
> to be processed. This should have been done in the 80s when image
> processing and computer typesetting became popular.

PL/I has had this facility since 1966.

> 3) It should be easy to plot graphs to a screen. This should have been
> done in the 80s when MacOS, Xwindows, and other graphical interfaces
> became popular.

Salford Fortran 90 does this; it's built in.

Ev. Drikos

unread,
Jul 25, 2018, 10:24:33 AM7/25/18
to
On 25/07/2018 10:10, Ron Shepard wrote:
> ...

Hello,

IMHO also, backwards compatibility is very important. Who wants to
adjust a project when the language specs change?

> 1) It should be easy to read and write spreadsheet files. This should
> have been done in the 80s when visicalc and excel and other spreadsheets
> became popular. Maybe this should be extended to database access too.

To my limited experience, in ERP business environments ie for a long
time the common practice had been "save an Excel spreadsheet as a tab
delimited file" (yet functions that load verbatim a whole Excel file are
provided in some ERP's; I don't remember very well the details).

Thereafter, loading a tab-formatted file is always feasible if either
the language provides the functionality (ie "read a line to my record"
or simply with an intrinsic "read the whole file to my array") or in
worst case one has to read and parse a file character by character.

Is this related to your comment or are you describing functionality that
is radically different and perhaps available to some tool you use?


Regards,
Ev. Drikos

Ev. Drikos

unread,
Jul 25, 2018, 1:00:16 PM7/25/18
to
On 25/07/2018 13:24, Ev. Drikos wrote:

> To my limited experience, in ERP business environments ie for a long
> time the common practice had been "save an Excel spreadsheet as a tab

To my limited experience, in ERP business environments ie for a long
time *one* common practice had been "save an Excel spreadsheet as a tab

spectrum

unread,
Jul 25, 2018, 4:24:01 PM7/25/18
to
On Wednesday, July 25, 2018 at 12:37:47 PM UTC+9, robin....@gmail.com wrote:

> This is the outcome of adapting the standard to suit some compiler
> vendors.

I am very much interested in this point... The current ambiguous specification
of .and. and .or. in Fortran (which is neither "eager" nor "short-circuit",
according to [4] in the page below)

https://en.wikipedia.org/wiki/Short-circuit_evaluation
[4] Fortran operators are neither short-circuit nor eager: the language specification allows the compiler to select the method for optimization.

is possibly a compromise to meet the requirement of multiple vendors?
(i.e., vendor A uses "eager" and vendor B uses "short-circuit" traditionally, and both
want to keep their old codes to run with their compilers, for example?)

# Btw, the table in the above page is much easier to read than mine above based
on RosettaCode... (though the number of languages is a bit fewer).

FortranFan

unread,
Jul 25, 2018, 4:37:43 PM7/25/18
to
On Tuesday, July 24, 2018 at 2:14:24 PM UTC-4, Dominik Gronkiewicz wrote:

> ..
>
> I think there's no doubt Fortran is way behind its competitors in many ways, and its good sides can barely make up for it. I am afraid if the mindset doesn't change, it will stay behind for a long time, before its ultimate death.


@Dominik Gronkiewicz,

There are many people including myself who have lots of concerns about the direction and pace in the advancement of the Fortran language standard. But those are almost entirely separate from anything in this thread. And also from the comments in your latest post which make little sense.

Most of what you write such as "fear from change for better", "If the standard was consistent, this code would never compile, because .. function evaluation would be predictable (as in C/C++)", "some seem to favor another philosophy: "keep the language broken and allow sh*tty programming habits", etc. is inaccurate and/or presumptuous and/or conflating of topics.

By the way, with "this code" I assume you mean the one listed upthread by @ john.coll...@gmail.com: considerable explanation has been provided to show it is a matter of refactoring that code, not with the language standard.

spectrum

unread,
Jul 25, 2018, 5:13:52 PM7/25/18
to
In my understanding, the concern of @Dominik and @john.coll... is that
the meaning of this kind of line

if ( n /= 0 .and. test1( n ) .and. test2( n ) ) call do_something()

is ill-defined if either (or both) of test1() and test2() have side effects,
or even if they are pure, their evaluation is ill-defined for n == 0.

IMO, the result of the above code is simply "undefined (= processor-dependent)"
in the current Fortran (correct?)

The opinion of Ron and yours is that one should "refactor" such a code as

if ( n /= 0 ) then
if ( test1( n ) ) then
if ( test2( n ) ) then
call do_something()
endif
endif
endif

to specify the order of evaluation explicitly. present() or allocated() always need
such nested constructs, which makes the code unnecessarily more verbose.

Apart from verbosity, the situation remains that the behavior of the first code is
"undefined". Though one could argue that it is the responsibility of the programmer
to avoid such an undefined code, it increases the danger of error-prone codes
to be more easily written.

Does the "optimization" gained by introducing a vendor-dependent optimization
really outweigh a more clearcut semantic? (In other words, does it really contribute
to making a practical code faster?) I doubt about this, because if one is
careful about the performance of the code, one would care about the order of
function evaluation (so that no redundant computations occur, for example)
rather than relying on optimization with potentially undefined results (in the
first code). In this sense, the first code is now essentially "dead" unless
all variables are simple logical variables (with no cost of evaluation), or all
the functions are pure and takes little time for evaluation, or one does not care
anything about the results/performance (which could be the case for students,
for example... XD)

But changing .and. and .or. to short-curciting is probably not possible because
the behavior of new and old compilers change silently (unless some serious efforts
taken).

My hope is then, please choose a bit simpler operator symbol than .andthen. and
.orelse. ... (they are simply long!)
&& and || not possible? (&& may be problematic, though...)

FortranFan

unread,
Jul 25, 2018, 6:24:00 PM7/25/18
to
On Wednesday, July 25, 2018 at 1:13:52 PM UTC-4, spectrum wrote:

> ..
>
> if ( n /= 0 .and. test1( n ) .and. test2( n ) ) call do_something()
>
> is ill-defined if either (or both) of test1() and test2() have side effects,
> or even if they are pure, their evaluation is ill-defined for n == 0.
>
> IMO, the result of the above code is simply "undefined (= processor-dependent)"


There is nothing ill-defined with the result of the above code in terms of the standard: do_something() will get invoked by all conforming processors if each of the 3 operands evaluates to TRUE; do_something() will not be invoked otherwise. Anything else such as what @john.coll.. showed about differences between processors in terms of manifestation of side effects (e.g., something is your test1 and/or test2 assuming they are functions) is immaterial as far as the standard is concerned.

What those other people you have named appear to want is to for the language standard itself to be entirely *prescriptive* about the order and short-circuiting (or lack thereof) of evaluation. I disagree with that notion entirely. It will hurt Fortran way more than it will help.

nrs...@gmail.com

unread,
Jul 25, 2018, 7:20:22 PM7/25/18
to
On Wednesday, July 25, 2018 at 1:24:00 PM UTC-5, FortranFan wrote:
> On Wednesday, July 25, 2018 at 1:13:52 PM UTC-4, spectrum wrote:
>
> > ..
> >
> > if ( n /= 0 .and. test1( n ) .and. test2( n ) ) call do_something()
> >
> > is ill-defined if either (or both) of test1() and test2() have side effects,
> > or even if they are pure, their evaluation is ill-defined for n == 0.
> >
> > IMO, the result of the above code is simply "undefined (= processor-dependent)"
>
>
> There is nothing ill-defined with the result of the above code in terms of the standard: do_something() will get invoked by all conforming processors if each of the 3 operands evaluates to TRUE; do_something() will not be invoked otherwise. Anything else such as what @john.coll.. showed about differences between processors in terms of manifestation of side effects (e.g., something is your test1 and/or test2 assuming they are functions) is immaterial as far as the standard is concerned.
>
Whatever your working definition of "ill-defined"/"undefined", spectrum explicitly used those words as synonyms for "processor-dependent". I think it's not productive to re-define your way to dismissing his example.

> What those other people you have named appear to want is to for the language standard itself to be entirely *prescriptive* about the order and short-circuiting (or lack thereof) of evaluation. I disagree with that notion entirely. It will hurt Fortran way more than it will help.
I think this correctly characterizes neither Dominik's nor john.coll..'s positions. The frustration expressed by them and others (to varying degrees of cogency) is about not having a convenient mechanism for guaranteeing order of evaluation. As you know (being aware of the .andthen./.orelse. proposal), wanting this facility is not equivalent to wanting to prescribe a language-wide order of evaluation.

FortranFan

unread,
Jul 25, 2018, 8:26:06 PM7/25/18
to
On Wednesday, July 25, 2018 at 3:20:22 PM UTC-4, nrs...@gmail.com wrote:

> .. The frustration expressed by them and others (to varying degrees of cogency) is about not having a convenient mechanism for guaranteeing order of evaluation. ..


Reads like "them and others" should evaluate whether the result of their "convenient mechanism" is ill-defined(= person-dependent)!

spectrum

unread,
Jul 25, 2018, 9:10:14 PM7/25/18
to
On Thursday, July 26, 2018 at 3:24:00 AM UTC+9, FortranFan wrote:
> On Wednesday, July 25, 2018 at 1:13:52 PM UTC-4, spectrum wrote:
>
> > if ( n /= 0 .and. test1( n ) .and. test2( n ) ) call do_something()
> >
> > is ill-defined if either (or both) of test1() and test2() have side effects,
> > or even if they are pure, their evaluation is ill-defined for n == 0.
> >
> > IMO, the result of the above code is simply "undefined (= processor-dependent)"
>
>
> There is nothing ill-defined with the result of the above code in terms of the standard: do_something() will get invoked by all conforming processors if each of the 3 operands evaluates to TRUE; do_something() will not be invoked otherwise. Anything else such as what @john.coll.. showed about differences between processors in terms of manifestation of side effects (e.g., something is your test1 and/or test2 assuming they are functions) is immaterial as far as the standard is concerned.


Please consider the situation, for example, where test1() and test2() update some module
variable(s) and also do_something() references the same module variables to perform
some task. Then, the behavior of do_something() is processor-dependent if the way of updating the module variables is processor-dependent.

# I use both "undefined" and "ill-defined" in the same meaning as
processor-dependent, but I will try to stick to the latter (for consistency)...
If I use the former two, please take them as equivalent to processor-dependent.
(From "processor", I imagine something like CPU etc, so feel a bit weird ;)


> What those other people you have named appear to want is to for the language standard itself to be entirely *prescriptive* about the order and short-circuiting (or lack thereof) of evaluation. I disagree with that notion entirely. It will hurt Fortran way more than it will help.

It is a bit difficult for me to understand the above sentences (sorry for the English
problem for me), but if it matters, I refer only to the logical operators (not talking about
general math expressions like func1() + func2() etc.) Though they are closely related,
I think it will be possible to focus on logical operators (if necessary, by limiting the context to those in IF statements and constructs).

-----
A bit more clarification:
The reason why I think it will be practically difficult to change the meaning (semantic) of
.and. and .or. to short-circuit ones is like this: Even if I writes a new code with a new
compiler with such new semantics, I may need to pass it to other people.
Then, the other people may use old compilers with old semantics, which
do not necessarily perform short circuit, so giving wrong results (depending
on compilers). This situation is to be avoided... (though there would be option-based
solution if all people are aware of such differences (in an ideal world)).

Thomas Koenig

unread,
Jul 25, 2018, 9:24:50 PM7/25/18
to
spectrum <septc...@gmail.com> schrieb:

> It is a bit difficult for me to understand the above sentences
> (sorry for the English problem for me), but if it matters, I refer
> only to the logical operators (not talking about general math
> expressions like func1() + func2() etc.) Though they are closely
> related, I think it will be possible to focus on logical operators
> (if necessary, by limiting the context to those in IF statements
> and constructs).

There is also the case of func1() + func1(). A compiler is allowed
to change this into var = func1(); var + var.

FortranFan

unread,
Jul 25, 2018, 10:06:03 PM7/25/18
to
On Wednesday, July 25, 2018 at 5:10:14 PM UTC-4, spectrum wrote:

> ..
> Please consider the situation, for example, where test1() and test2() update some module
> variable(s) and also do_something() references the same module variables to perform
> some task. Then, the behavior of do_something() is processor-dependent if the way of updating the module variables is processor-dependent.
> ..


@spectrum,

Take it one aspect at a time given your instruction:
if ( (n /= 0) .and. test1(n) .and. test2(n) ) call do_something()

You write, "even if they are pure, their evaluation is ill-defined for n == 0"

Can you show an example standard-conforming program with PURE test1 and test2 functions where the evaluation becomes processor-dependent when n equals zero?

JCampbell

unread,
Jul 26, 2018, 1:41:23 AM7/26/18
to
On Thursday, July 26, 2018 at 7:10:14 AM UTC+10, spectrum wrote:
>
> Please consider the situation, for example, where test1() and test2() update some module
> variable(s) and also do_something() references the same module variables to perform
> some task. Then, the behavior of do_something() is processor-dependent if the way of updating the module variables is processor-dependent.
>

Surely the programmer should take some responsibility for this "situation".
Is there any agreement it is a bad approach when the outcome is processor-dependent ? so explicitly call the impure functions.

robin....@gmail.com

unread,
Jul 26, 2018, 3:32:21 AM7/26/18
to
On Thursday, July 26, 2018 at 3:13:52 AM UTC+10, spectrum wrote:
> In my understanding, the concern of @Dominik and @john.coll... is that
> the meaning of this kind of line
>
> if ( n /= 0 .and. test1( n ) .and. test2( n ) ) call do_something()
>
> is ill-defined if either (or both) of test1() and test2() have side effects,
> or even if they are pure, their evaluation is ill-defined for n == 0.

It might be that they are ill-defined for that case, maybe not.
Or if test1 and test2 are arrays, having lower bounds of 1,
a reference to either would be out-of-bounds.

> IMO, the result of the above code is simply "undefined (= processor-dependent)"
> in the current Fortran (correct?)
>
> The opinion of Ron and yours is that one should "refactor" such a code as
>
> if ( n /= 0 ) then
> if ( test1( n ) ) then
> if ( test2( n ) ) then
> call do_something()
> endif
> endif
> endif
>
> to specify the order of evaluation explicitly. present() or allocated() always need
> such nested constructs, which makes the code unnecessarily more verbose.
>
> Apart from verbosity, the situation remains that the behavior of the first code is
> "undefined". Though one could argue that it is the responsibility of the programmer
> to avoid such an undefined code, it increases the danger of error-prone codes
> to be more easily written.

Do we really need constructs that are so easily written as bad,
in the first place, and probably easily overlooked in a visual check?

In the past, bad code was readily written in FORTRAN,
and erroneous code passed by the compiler unnoticed.
The classic ones were O instead of zero (0),
typing beyond column 72, mis-spelled variable names,
and the like.

> Does the "optimization" gained by introducing a vendor-dependent optimization
> really outweigh a more clearcut semantic? (In other words, does it really contribute
> to making a practical code faster?) I doubt about this,

So do I. As well, it wastes programmer time.
The code might be faster, but what's the point if the results are wrong
without warning?
Message has been deleted

robin....@gmail.com

unread,
Jul 26, 2018, 4:15:53 AM7/26/18
to
"n" might be used as a subscript [though that is more likely if the test
were n > 0].

robin....@gmail.com

unread,
Jul 26, 2018, 4:24:36 AM7/26/18
to
On Thursday, July 26, 2018 at 7:24:50 AM UTC+10, Thomas Koenig wrote:

> There is also the case of func1() + func1(). A compiler is allowed
> to change this into var = func1(); var + var.

If a programmer wrote that, he is expecting the calls to produce different
results for each invocation. [otherwise he would have written 2*func1() ]

steve kargl

unread,
Jul 26, 2018, 5:06:22 AM7/26/18
to
Doesn't matter what the programmer (who apparently has not read the
Fortran standard) expects. Thomas is correct. The Fortran standard
permits the optimization.

--
steve

Ron Shepard

unread,
Jul 26, 2018, 5:08:34 AM7/26/18
to
If func1() does result in different values on different invocations,
then is it legal in fortran to even write the expression
func1()+func1()? I think it isn't, but this is part of function and
expression evaluation in fortran that is unclear to me.

$.02 -Ron Shepard

robin....@gmail.com

unread,
Jul 26, 2018, 7:55:49 AM7/26/18
to
On Thursday, July 26, 2018 at 3:08:34 PM UTC+10, Ron Shepard wrote:
It's probably not valid Fortran, because code can be avoided in any
expression (not just logical).

I also think that writing it as
x = func1()
y = func1()
z = x + y
is not guaranteed to make separate invocations of func1
when an optimiser is at work.

robin....@gmail.com

unread,
Jul 26, 2018, 8:00:07 AM7/26/18
to
On Thursday, July 26, 2018 at 3:06:22 PM UTC+10, steve kargl wrote:
I'm aware of that. Asking everyone to read the standard
(including beginners) is not productive, because so much of it
is gobbledegook.
Ample evidence of that is to be found in official "clarifications"/

Gary Scott

unread,
Jul 26, 2018, 12:21:29 PM7/26/18
to
What about a simple change to syntax to inform the compiler that a
function is known to have side effects that you want to be executed?

if (ivar /= 0 .and. @f(x)) ...

john.coll...@gmail.com

unread,
Jul 26, 2018, 12:34:33 PM7/26/18
to
It isn't legal for a function invocation to change the value of any other object in the same statement. I found this in the Fortran 2008 standard, but I can't remember where it is and have spent the last half hour failing to find it again. Can anyone help?

Arguably, it may therefore be illegal for two function invocations (Whether of the same or of different functions) to have order-dependent side-effects - either function invocation would affect the behaviour of the other. If this is the case, the only codes which would change behaviour if short-circuiting were mandated are already not standard conforming.

My position is that the standard should be written in such a way that a standard-conforming code should produce the same results in any environment, except for the effects of numerical drift, random number generation and time dependencies.

Best wishes,
John

FortranFan

unread,
Jul 26, 2018, 2:07:11 PM7/26/18
to
On Thursday, July 26, 2018 at 8:34:33 AM UTC-4, john.coll...@gmail.com wrote:

> ..
> It isn't legal for a function invocation to change the value of any other object in the same statement. ..


You didn't have to look far, it was pointed out to you in this thread itself a couple of weeks ago:
https://groups.google.com/d/msg/comp.lang.fortran/OzSX0GC1pWU/f4xuq4zyBQAJ

> My position is that the standard should be written in such a way that a standard-conforming code should produce the same results in any environment ..

This has been discussed upthread in the context of that code example of yours: processor-dependent aspects are integral to the standard from its origin and your position is untenable.

What is possible though is for coders to generally write standard-conforming code that can produce "same" results with all standard-conforming processors. With your own example, you know, I know, and the readers know minor changes to the code will yield the same results with all the processors you have tried; right there is the refactorization option for you and your outfit (Ltd company?).

FortranFan

unread,
Jul 26, 2018, 2:20:57 PM7/26/18
to
On Wednesday, July 25, 2018 at 11:39:24 PM UTC-4, robin....@gmail.com wrote:

> ..
> It is easy for do_something to be invoked when one, two, or three
> operands is/are true.
> And it depends on the compiler and maybe the level of optimisation.
> So, even on the same compiler, different actions take place depending
> on the optimisation level requested.
> ..

In the context of @spectrum's code which had

if ( n /= 0 .and. test1( n ) .and. test2( n ) ) call do_something()

and keeping in mind section 7.1.4 on Evaluation of Expressions in the current Fortran standard, I think the above comments by @robin.. are inaccurate, particularly "It is easy for do_something to be invoked when one, two, or three operands is/are true".

I'll be keen to see if @john.. (who appears to have access to a lot of different processors), @spectrum et al. can prove me wrong with actual code executed with a standard-conforming processor.

robin....@gmail.com

unread,
Jul 26, 2018, 4:13:03 PM7/26/18
to
On Friday, July 27, 2018 at 12:20:57 AM UTC+10, FortranFan wrote:
> On Wednesday, July 25, 2018 at 11:39:24 PM UTC-4, robin....@gmail.com wrote:
>
> > ..
> > It is easy for do_something to be invoked when one, two, or three
> > operands is/are true.
> > And it depends on the compiler and maybe the level of optimisation.
> > So, even on the same compiler, different actions take place depending
> > on the optimisation level requested.
> > ..
>
> In the context of @spectrum's code which had
>
> if ( n /= 0 .and. test1( n ) .and. test2( n ) ) call do_something()
>
> and keeping in mind section 7.1.4 on Evaluation of Expressions in the current Fortran standard, I think the above comments by @robin.. are inaccurate, particularly "It is easy for do_something to be invoked when one, two, or three operands is/are true".

You're right. I screwed that up. I was thinking on terms of logical OR,
not AND.

What I should have said was that if n = 0, test1 and test2 might not be invoked.

Ron Shepard

unread,
Jul 26, 2018, 4:55:44 PM7/26/18
to
There are two issues with this, one is the order that the function calls
are made, and the other is whether one or two calls are made in order to
evaluate the final result.

In the case of func1()+func1(), it does not matter which function is
invoked first, the end result of the expression would be the same either
way because the expression is symmetrical. But what if we change it
slightly to

func1() + 3 * func1()

Now the order of evaluation affects the result, and the issue of how
many function calls are actually invoked is also still in play. Just to
give an example, suppose func1() returns the number of times it has been
invoked, 1 for the first time and 2 for the second time. Here is a table
that gives the possible outcomes for a single invocation, and for the
two possible results with two invocations.

single: 4 = 4*1
LR: 7 = 1+3*2
RL: 5 = 2+3*1

And of course, there is also the possibility that the compiler could
look ahead at the code and realize that the result of this expression is
not used at all, in which case func1() would not be invoked at all (dead
code elimination). That would have no local affect, but it would affect
subsequent evaluations of func1() either in that subprogram or in other
subprograms.

How much of this is in play when the code is rewritten as separate
statements?

x = func1()
y = 3 * func1()
z = x + y

What if x, y, and z are not referenced thereafter? Can an optimizer
legitimately eliminate all three statements as dead code? If z is
evaluated, then are the three possible values still allowed?

Here is another point that I think has not been mentioned in this
thread. The logical operators .and. and .or. (and the arithmetic
operators * and +) are commutative. In fortran, it does not matter if
you write A.and.B or B.and.A, the result is the same. This is why the
compiler is allowed to rearrange expressions like this in the first
place during evaluation, it mimics the underlying logical and
mathematical relations. The idea of introducing short-circuit operators
destroys this symmetry in those operators.

Finally, a separate issue, the fortran standards have always categorized
the result of such code as "undefined" and the code as nonconforming,
and for nonconforming code, the processor is allowed to do anything,
including starting WWIII. Is there any advantage to allowing another
category of results? In the above example, z would be defined, but the
processor would be required to return any of the three possible values,
and it would not be allowed to start WWIII. "Defined" but not "Well
Defined," or "Defined" but "Ambiguous" I guess would be the way to
characterize it. This is effectively what programmers have been doing
all along with code like this. They expect the results to be valid
integers or valid floating point values, and perhaps the results satisfy
other properties too, but the computed values are not strictly well
defined and might change with optimization level or compiler revisions
and such.

$.02 -Ron Shepard




steve kargl

unread,
Jul 27, 2018, 2:28:18 AM7/27/18
to
The code is then non-conforming. From F2018 (draft) 10.1.4,

the evaluation of a function reference shall neither affect nor be affected by the evaluation
of any other entity within the statement;

--
steve

robin....@gmail.com

unread,
Jul 27, 2018, 3:04:30 AM7/27/18
to
Spot the programming error (from Rosetta Code)

program sum_of_powers
implicit none

integer, parameter :: maxn = 249
integer, parameter :: dprec = selected_real_kind(15)
integer :: i, x0, x1, x2, x3, y
real(dprec) :: n(maxn), sumx

n = (/ (real(i, dprec)**5, i = 1, maxn) /)

outer: do x0 = 1, maxn
do x1 = 1, maxn
do x2 = 1, maxn
do x3 = 1, maxn
sumx = n(x0)+ n(x1)+ n(x2)+ n(x3)
y = 1
do while(y <= maxn .and. n(y) <= sumx)
if(n(y) == sumx) then
write(*,*) x0, x1, x2, x3, y
exit outer
end if
y = y + 1
end do
end do
end do
end do
end do outer

end program

Thomas Koenig

unread,
Jul 27, 2018, 7:11:48 AM7/27/18
to
Ron Shepard <nos...@nowhere.org> schrieb:

> How much of this is in play when the code is rewritten as separate
> statements?
>
> x = func1()
> y = 3 * func1()
> z = x + y
>
> What if x, y, and z are not referenced thereafter? Can an optimizer
> legitimately eliminate all three statements as dead code?

No. For this code, func1() has to be evaluated twice.

john.coll...@gmail.com

unread,
Jul 27, 2018, 9:51:48 AM7/27/18
to
(Thank you FortranFan for:
You didn't have to look far, it was pointed out to you in this thread itself a couple of weeks ago:
https://groups.google.com/d/msg/comp.lang.fortran/OzSX0GC1pWU/f4xuq4zyBQAJ )

It seems that we have two issues here:

i. If two or more functions are invoked in a statement and they have side effects which can affect each other, the code is not standard conforming and the results are not defined by the standard. The only problem is in finding and fixing occurrences.

ii. If a function occurs in a logical expression of the form, for example:
IF ( (i > 0) .AND. lf(i) ) CALL something
where lf is a impure logical function, and the processor is permitted but not required to short-circuit the logical tests, the side effects of lf may or may not occur and the results of the entire program are undefined.

Is there anything in the standard to resolve case ii? Should there be?

Best wishes,
John

steve kargl

unread,
Jul 27, 2018, 2:27:56 PM7/27/18
to
Well, there is F2018, 10.1.7 and its Note 10.28.

It does not matter whether lf is pure or impure. The permits shorting-circuiting.

--
steve

Message has been deleted

FortranFan

unread,
Jul 27, 2018, 3:20:51 PM7/27/18
to
On Friday, July 27, 2018 at 5:51:48 AM UTC-4, john.coll...@gmail.com wrote:

> ..
> ii. If a function occurs in a logical expression of the form, for example:
> IF ( (i > 0) .AND. lf(i) ) CALL something
> where lf is a impure logical function, and the processor is permitted but not required to short-circuit the logical tests, the side effects of lf may or may not occur and the results of the entire program are undefined.
>
> Is there anything in the standard to resolve case ii? Should there be?
> ..


@John,

Re: your first in point ii, "Is there anything in the standard to resolve case ii?" your earlier comments here and elsewhere suggest that rather than "anything", what you may have is something *specific* in your mind such as whether the standard includes the necessary fatwa(s) against the "haram" possibility that "the side effects of lf may or may not occur and the results of the entire program are undefined". You know the answer to the latter is no. However coming back to your first question though, you already know there are *lots of things* in the standard that enable code to be written so that program execution results are the same with all conforming processors. That is about all the standard can do, I think.

By the way, with your example in this thread at the link:
https://groups.google.com/d/msg/comp.lang.fortran/OzSX0GC1pWU/y53XzdXCBAAJ

say you modify the main program as shown below. Can you please test it against all the processors you have tried and report here whether the results of the entire program (as you cal them) remain undefined?

--- modified main ---
PROGRAM t
USE m
LOGICAL,EXTERNAL :: f1,f2
LOGICAL :: l1, l2

CALL set_conditions

l1 = f1()
l2 = f2()
IF (l1 .AND. l2) THEN
WRITE(*,'("Condition .TRUE.")')
ELSE
WRITE(*,'("Condition .FALSE.")')
ENDIF

END PROGRAM t
--- modified main ---

Thanks,

john.coll...@gmail.com

unread,
Jul 27, 2018, 3:57:29 PM7/27/18
to
Under all of the following, with default optimisation and under gfortran with the highest level of optimisation available, both functions are always called.

I haven't been able to test ifort - I don't have access to our ifort machine today. I will report that if it is any different (Which I doubt).

CVF 6.6.C
FTN95 4.9.0
G95 (GCC 4.0.3 (g95 0.94!) Jan 17 2013)
GNU Fortran (Ubuntu 7.1.0-10ubuntu1~16.04.york0) 7.1.0
GNU Fortran (Ubuntu 8-20180414-1ubuntu2) 8.0.1 20180414 (experimental) [trunk revision 259383]
Oracle developer Studio 12.6
pgfortran 18.4-0 64-bit Linux -tp haswell

I believe (And hope!) it is, as @FortranFan wrote, possible to write code with unambiguous flow. But I remain unconvinced that ambiguity is either necessary or desirable.

Best wishes,
John

john.coll...@gmail.com

unread,
Jul 27, 2018, 4:23:02 PM7/27/18
to
I added ifort (IFORT) 16.0.1 20151021 and for all of the compilers set the highest available optimisation. Both functions were still invoked in all cases.

Good!

John

FortranFan

unread,
Jul 27, 2018, 6:52:42 PM7/27/18
to
On Friday, July 27, 2018 at 11:57:29 AM UTC-4, john.coll...@gmail.com wrote:

> .. But I remain unconvinced that ambiguity is either necessary or desirable.
> ..


@John,

Thanks for your follow-up re: the test I requested.

Re: your comment implying the position of the Fortran standard is that "ambiguity is either necessary or desirable," it is inaccurate.

I find you have really only "ambiguous" case overall involving an AND operation and results which are really side effects of impure functions. Underpinning the differences in results of various processors is effectively one sentence in the standard (section 7.1.7 paragraph 1), "It is not necessary for a processor to evaluate all of the operands of an expression, or to evaluate entirely each operand, if the value of the expression can be determined otherwise." And the case you show falls out with the simplest of determination in the truth table. No change to the Fortran standard on account of such a situation seems justifiable to me. I will suggest you show other cases of ambiguity that have more heft to them.

Ron Shepard

unread,
Jul 28, 2018, 1:16:46 AM7/28/18
to
On 7/27/18 11:23 AM, john.coll...@gmail.com wrote:
[...]

>>> PROGRAM t
>>> USE m
>>> LOGICAL,EXTERNAL :: f1,f2
>>> LOGICAL :: l1, l2
>>>
>>> CALL set_conditions
>>>
>>> l1 = f1()
>>> l2 = f2()
>>> IF (l1 .AND. l2) THEN
>>> WRITE(*,'("Condition .TRUE.")')
>>> ELSE
>>> WRITE(*,'("Condition .FALSE.")')
>>> ENDIF
[...]
> I added ifort (IFORT) 16.0.1 20151021 and for all of the compilers set the highest available optimisation. Both functions were still invoked in all cases.

If you are willing to experiment a little more, I would like to know
about the following variations too.

l1 = f1()
IF (l1 .AND. f2()) THEN

and the symmetrical case

l2 = f2()
IF (f1() .AND. l2) THEN

It seems like both of these should short circuit with sufficiently
aggressive optimization, the first one left to right and the second one
right to left.

$.02 -Ron Shepard

robin....@gmail.com

unread,
Jul 28, 2018, 6:51:25 AM7/28/18
to
It seems that my remark about this program was not sufficient.

Here's a clue:

The error is in the context of this thread.

Louis Krupp

unread,
Jul 28, 2018, 9:53:21 AM7/28/18
to
On Thu, 26 Jul 2018 20:04:28 -0700 (PDT), robin....@gmail.com
wrote:

>Spot the programming error (from Rosetta Code)
>
>program sum_of_powers
> implicit none
>
> integer, parameter :: maxn = 249
> integer, parameter :: dprec = selected_real_kind(15)
> integer :: i, x0, x1, x2, x3, y
> real(dprec) :: n(maxn), sumx
>
> n = (/ (real(i, dprec)**5, i = 1, maxn) /)
>
>outer: do x0 = 1, maxn
> do x1 = 1, maxn
> do x2 = 1, maxn
> do x3 = 1, maxn
> sumx = n(x0)+ n(x1)+ n(x2)+ n(x3)
> y = 1

There is nothing in the following line to keep n(y) from being
computed even if y > maxn.
> do while(y <= maxn .and. n(y) <= sumx)

> if(n(y) == sumx) then
> write(*,*) x0, x1, x2, x3, y
> exit outer
> end if
> y = y + 1
> end do
> end do
> end do
> end do
> end do outer
>
>end program

Louis

john.coll...@gmail.com

unread,
Jul 28, 2018, 10:12:46 AM7/28/18
to
Interesting test: Here is the program

MODULE m
LOGICAL :: l1,l2
CONTAINS
SUBROUTINE set_conditions
WRITE(*,'("l1: ",$)')
READ(*,'(L1)')l1
WRITE(*,'("l2: ",$)')
READ(*,'(L2)')l2
END SUBROUTINE set_conditions
END MODULE m

! --- modified main ---
PROGRAM t
USE m
LOGICAL,EXTERNAL :: f1,f2
!!! LOGICAL :: l1, l2 (Already in MODULE m)

CALL set_conditions

WRITE(*,'(/,"FortranFan''s test")')
l1 = f1()
l2 = f2()
IF (l1 .AND. l2) THEN
WRITE(*,'("Condition .TRUE.")')
ELSE
WRITE(*,'("Condition .FALSE.")')
ENDIF

WRITE(*,'(/,"Ron Shepard: l1 = f1() first")')
l1 = f1()
IF (l1 .AND. f2()) THEN
WRITE(*,'("Condition .TRUE.")')
ELSE
WRITE(*,'("Condition .FALSE.")')
ENDIF

WRITE(*,'(/,"Ron Shepard: l2 = f2() first")')
l2 = f2()
IF (f1() .AND. l2) THEN
WRITE(*,'("Condition .TRUE.")')
ELSE
WRITE(*,'("Condition .FALSE.")')
ENDIF


END PROGRAM t
! --- modified main ---

LOGICAL FUNCTION f1()
USE m
WRITE(*,'("f1 was called")')
f1 = l1
END FUNCTION f1

LOGICAL FUNCTION f2()
USE m
WRITE(*,'("f2 was called")')
f2 = l2
END FUNCTION f2

The compilers tested were:

CVF 6.6.C
FTN95 4.9.0
G95 (GCC 4.0.3 (g95 0.94!) Jan 17 2013)
GNU Fortran (Ubuntu 7.1.0-10ubuntu1~16.04.york0) 7.1.0
GNU Fortran (Ubuntu 8-20180414-1ubuntu2) 8.0.1 20180414 (experimental) [trunk revision 259383]
ifort (IFORT) 16.0.1 20151021
Oracle developer Studio 12.6
pgfortran 18.4-0 64-bit Linux -tp haswell

The results were:

l1 = f1(1) first l2 = f2() first

CVF f1 only f2 only
FTN95 Both Both
gfortran 7.1.0 f1 only Both
gfortran 8.0.1 f1 only Both
g95 f1 only Both
ifort Both Both
pgfortran f1 only f2 only
SunStudio f1 only Both

The results were exactly the same with optimisation turned off and with the highest available optimisation (!)

If the results of an expression include the side-effects of the function invoked then both functions should always be called. But are the side effects to be included in the results? I am not sure that the standard says so.

Is the code standard-conforming? The two functions affect one another in that they cause the output to be written to different lines.

Our refactoring tool converts:
IF ( f1() .AND. f2() ) THEN
To Ron Shepard's first example. I am no longer sure that this is a good idea. Should it call both functions explicitly?

Best wishes,
John

dpb

unread,
Jul 28, 2018, 2:24:42 PM7/28/18
to
On 7/28/2018 5:12 AM, john.coll...@gmail.com wrote:
...

> If the results of an expression include the side-effects of the function invoked then both functions
should always be called. But are the side effects to be included in the
results? I am not sure that the standard says so.


I'm personally confident the Standard does _NOT_ include side effects in
its definition -- "

"It is not necessary for a processor to evaluate all of the operands of
an expression, or to evaluate entirely each operand, if the value of the
expression can be determined otherwise."(*)

"The expression" in my reading is that result of the evaluation only in
my interpretation; since Fortran uses independent program units for
compilation how's the processor to even know there _are_ side effects?

The only solution to that "problem" is to independently evaluate every
function irrespective of whether the evaluation is needed for the
expression or not and that is clearly not required by the Standard so
one backs into the same conclusion.

(*) Altho I think the 'or' should be 'nor', pedantically...or at least
Mrs. Varah would have marked it so! :)

...

It is loading more messages.
0 new messages