Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28383 Discussions

different behaviour from gfortran when printing result of function that prints itself

AAK
Novice
2,036 Views

Hi everyone,

ifort and gfortran yield different results when executing a print-statement that contains a function call that itself does printing.

I found it hard to search for existing topics for this behaviour - I hope this is no duplicate...

However, the following code

 

logical function func_that_does_printing() result(bool)
implicit none
  print *, 'exec func_that_does_printing'
  bool=.true.
end function 
program p
implicit none
logical, external :: func_that_does_printing
  print *, ' result of func_that_does_printing=', func_that_does_printing()
end program 

 

 executes differently with ifort (2021.5.0 20211109) and gfortran(7.5.0

 

ifort -O0 print-in-print.f90 && ./a.out        
exec func_that_does_printing
T
gfortran -O0 print-in-print.f90 && ./a.out  
 result of func_that_does_printing= exec func_that_does_printing
T 

 

 I was expecting, that first of all the function is evaluated in some dummy variable and afterwords the "original" print (from within the program) is executed. Hence I was expecting stdout to be

 

exec func_that_does_printing
result of func_that_does_printing=T

 

Could someone explain if  either`ifort` or `gfortran` is "right" and how such statements are executed on the low level?

Greetings!

0 Kudos
1 Solution
Ron_Green
Moderator
2,008 Views

We had a look at this.  Our efforts are to get IFX working for legal code first, and to try to reach parity with ifort by the end of this year 2022.  Maybe in a few years we can revisit this example if it's still of concern.  Bigger priorities for several years ahead.  Thank you for bringing this example to our attention.  Thanks for your analysis, Steve!

View solution in original post

13 Replies
FortranFan
Honored Contributor II
2,025 Views

@AAK ,

The code you show attempts recursive I/O on output_unit which, if I recall correctly, is not supported.  Under the circumstances, my understanding is the program will show processor-dependent behavior and the question as to who is "right" is immaterial.  The program can also encounter a run-time error in such a situation.

If possible, avoid IO in function subprograms, strive for "PURE" functions!  Using subroutines for IO is better you will notice!

0 Kudos
Steve_Lionel
Honored Contributor III
2,023 Views

They're both right. 

Your program violates the Fortran standard, so the result is undefined.

"An input/output statement that is executed while another input/output statement is being executed is a recursive input/output statement. A recursive input/output statement shall not identify an external unit that is identified by another input/output statement being executed except that a child data transfer statement may identify its parent data transfer statement external unit." (F2018 12.12p2)

It does bother me that Intel Fortran doesn't give a run-time error for "recursive I/O" here - it used to. I think that is a bug.

AAK
Novice
2,008 Views

@FortranFan @Steve_Lionel 

Thanks for the quick responses!!
I use the print statements in question to report errors from many places in my code. They only execute when errors happen anyway, so there is no big loss when they result in errors themselves. In the specific case above, I was wondering why my print-output was gone.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,983 Views

Steve,

I note that with respect to an IF statement, e.g. IF(expression .op. expression) that there is no specified order or shunting of expression evaluation as is with C.

Applying this to the print statement, e.g.

print *,funcA(), funcB()

That I am guessing that there is no specified order of execution of the functions but only an order placement for the results. IOW should funcA and funcB share state variables, the results of the functions may depend on the order in which they are called. And thus the results would be implementation dependent. What I intend to say is that this discrepancy in results between implementation may not be limited to recursive I/O.

Jim Dempsey

0 Kudos
Ron_Green
Moderator
2,009 Views

We had a look at this.  Our efforts are to get IFX working for legal code first, and to try to reach parity with ifort by the end of this year 2022.  Maybe in a few years we can revisit this example if it's still of concern.  Bigger priorities for several years ahead.  Thank you for bringing this example to our attention.  Thanks for your analysis, Steve!

Ron_Green
Moderator
1,998 Views

@AAK examples like this are great fun.  They give us all a chance to dig into The Standard, discuss, and learn.  Thanks for bringing it here.  

0 Kudos
AAK
Novice
1,994 Views

@Ron_Green Thanks for caring about it in the first place!

0 Kudos
Steve_Lionel
Honored Contributor III
1,809 Views

Hi Jim,

For expressions, I will just point you to Doctor Fortran in "Order! Order!" - Doctor Fortran (stevelionel.com)

As for the print statement issue, the standard is quite clear that there IS an order. The following quotes are from F2018, emphasis mine:

"Data are transferred between the file and the entities specified by the input/output list or namelist. The list items are processed in the order of the input/output list for all data transfer statements except namelist data transfer statements. 

All values needed to determine which entities are specified by an input/output list item are determined at the beginning of the processing of that item.

All values are transmitted to or from the entities specified by a list item prior to the processing of any succeeding list item for all data transfer statements. " (12.6.4.5.1p1-3)

Therefore, in your example funcA is always called before funcB. It is valid for the funcA call to have an effect on the result of the funcB call. There is a prohibition on having any side-effect on the internal file for internal I/O.

0 Kudos
IanH
Honored Contributor II
1,697 Views

@Steve_Lionel wrote:

Hi Jim,

..
Therefore, in your example funcA is always called before funcB. It is valid for the funcA call to have an effect on the result of the funcB call.

"Except in those (not relevant) cases: the evaluation of a function reference shall neither affect nor be affected by the evaluation of any other entity within the statement"

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,653 Views

>>prior to the processing of any succeeding list item 

It could be argued that this statement is subject to interpretation. 

IOW Is the succeeding list item the result of the function call or the (start of) computation of the function therein.

As well as: "the processing" clearly includes the formatting (or copying in lack of formatting) of the results data.

I will state that this is nitpicking, it would remove subjective interpretation if the rule was more explicit for this.

Jim Dempsey

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,641 Views

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

Therefore, when you break that rule, you enter implementation territory.

Jim Dempsey

0 Kudos
Steve_Lionel
Honored Contributor III
1,593 Views

The text Ian quoted is not relevant here, as he says.

The succeeding list item is the function call, before it is called. I see no ambiguity here.

0 Kudos
IanH
Honored Contributor II
1,544 Views

I think the bit of the standard I quoted is relevant - apologies for any confusion but my "not relevant" bit was referring to the exceptions to the rule that I elided for conciseness (test expression in an IF statement, etc).

The ordering rules cover potential ambiguity for things other than function references with side effects, most obviously ... input!

0 Kudos
Reply