|
forums.silverfrost.com Welcome to the Silverfrost forums
|
View previous topic :: View next topic |
Author |
Message |
simon
Joined: 05 Jul 2006 Posts: 268
|
Posted: Thu Nov 26, 2015 4:12 am Post subject: Incorrect value of PRESENT |
|
|
The following example of code seems to return an incorrect value for the intrinsic function PRESENT. The main program calls subroutine s1, passing a function for s1 to call. This function has an optional argument, but s1 does not pass this argument. However, the intrinsic function PRESENT returns .true.. The problem only seems to occur because the function f is passed as a procedure argument.
Code: | MODULE m1
CONTAINS
SUBROUTINE s1(f)
INTEGER, EXTERNAL :: f
INTEGER :: j
j=f()
END SUBROUTINE s1
INTEGER FUNCTION f1 (i)
INTEGER, INTENT(IN), OPTIONAL :: i
PRINT *, PRESENT (i)
f1=0
END FUNCTION f1
END MODULE m1
PROGRAM p
USE m1
CALL s1 (f1)
END PROGRAM p | [/code] |
|
Back to top |
|
|
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 7924 Location: Salford, UK
|
Posted: Thu Nov 26, 2015 9:46 am Post subject: |
|
|
gFortran gives the same incorrect result.
It could be a nasty one to try to fix.
I will log it for investigation. |
|
Back to top |
|
|
mecej4
Joined: 31 Oct 2006 Posts: 1886
|
Posted: Thu Nov 26, 2015 12:33 pm Post subject: |
|
|
My reading of the test code is a bit different. The program is non-conforming for the reason given below, and the compiler is not required to diagnose the problem.
The caller of a subprogram with an OPTIONAL argument must be provided with an explicit interface to the callee. In the test code, instead of such an interface being provided, the argument is declared EXTERNAL, so the compiler is going to use an implicit interface which is incorrect. In such a situation, no compiler is likely to diagnose the problem unless run-time checks are requested for argument consistency. |
|
Back to top |
|
|
simon
Joined: 05 Jul 2006 Posts: 268
|
Posted: Thu Nov 26, 2015 2:14 pm Post subject: |
|
|
Many thanks for the quick responses. I have tested NAGWare, and that has the same problem also. The suggestion to include an explicit interface works (see below). I had thought the interface was not needed since the function is in module m1. However, it does seem that the EXTERNAL statement over-rides that.
Code: | MODULE m1
CONTAINS
SUBROUTINE s1(f)
INTERFACE
INTEGER FUNCTION f (i)
INTEGER, INTENT(IN), OPTIONAL :: i
END FUNCTION f
END INTERFACE
INTEGER :: j
j=f()
END SUBROUTINE s1
INTEGER FUNCTION f1 (i)
INTEGER, INTENT(IN), OPTIONAL :: i
PRINT *, PRESENT (i)
f1=0
END FUNCTION f1
END MODULE m1
PROGRAM p
USE m1
CALL s1 (f1)
END PROGRAM p |
|
|
Back to top |
|
|
mecej4
Joined: 31 Oct 2006 Posts: 1886
|
Posted: Thu Nov 26, 2015 4:05 pm Post subject: |
|
|
I think that the presence of optional arguments in the test program is a red herring. The real point to note is that when entities that are accessible by host association are re-declared in a local scope, the host entities become hidden. Please see "16.5.1.4 Host association", item 2(10) of F2008. Here is an example to illustrate this, using subprograms for which no explicit interface is needed:
Code: |
MODULE m1
implicit none
CONTAINS
SUBROUTINE s1(f1,i)
INTEGER, EXTERNAL :: f1
INTEGER :: i
i=f1(i)
RETURN
END SUBROUTINE s1
INTEGER FUNCTION f1 (i)
INTEGER, INTENT(IN) :: i
PRINT *, 'F1, arg_in = ',i
f1=10
END FUNCTION f1
INTEGER FUNCTION f2 (i)
INTEGER, INTENT(IN) :: i
PRINT *, 'F2, arg_in = ',i
f2=20
END FUNCTION f2
END MODULE m1
PROGRAM p
USE m1
IMPLICIT NONE
INTEGER :: i = 50
CALL s1 (f2,i)
END PROGRAM p
|
The entities named 'f1' on lines 4 and 10 are distinct from each other. In fact, the running of the program should be unchanged if the body of the module procedure f1 is removed completely. |
|
Back to top |
|
|
LitusSaxonicum
Joined: 23 Aug 2005 Posts: 2388 Location: Yateley, Hants, UK
|
Posted: Sat Nov 28, 2015 7:00 pm Post subject: |
|
|
Mecej4: I think that your first answer was right in the context of the question asked, and that is that a subprogram with optional arguments needs to have an explicit interface. Without the explicit interface the compiler should be building straightforward traditional subprogram code in which all the arguments are not optional, because it has no way of knowing from the perspective of the caller that the arguments are optional.
It is all too easy for a programmer to assume that the compiler takes into account absolutely every statement in the source code as it works through the file, and can determine the programmer’s intention from even the flimsiest of hints, but there is clearly a limitation to how far ahead in the source code it can look.
You didn’t put it in your own demonstrator, but it seems to me that if one does write a subprogram with optional arguments the first important step that one should take is to check that they are in fact present before using them. Probably the model for this lies in the treatment of the Clearwin+ function WINIO@ where the presence of other arguments is dependent on what is put into the first string argument. The traditionalist like myself has his mind boggled that this works at all, let alone as reliably as it does!
In fact, in your demonstration code it looks to me as if the declaration of F1 as being EXTERNAL is unnecessary* in subroutine S1, as F1 is simply used and not passed as an argument to another routine. It seemed to me at first that program P needed F2 declared as EXTERNAL, although because module M1 contains integer function F2 it is treated differently (as an internal function, not an external one, i.e. as one would treat a traditional statement function).
Eddie
*Not just unnecessarily, but probably incorrectly. I know that EXTERNAL is a rather benign thing to have in a declaration, and in the past I have been advised to put named BLOCK DATA routines in EXTERNAL statements so that the linker looks for them, but never having used named BLOCK DATA then the advice fell on deaf ears. |
|
Back to top |
|
|
mecej4
Joined: 31 Oct 2006 Posts: 1886
|
Posted: Sat Nov 28, 2015 7:52 pm Post subject: |
|
|
Eddie, thanks for your comments; I agree with your point that EXTERNAL was unnecessary here, except for making the code more readable. Since f1 is a dummy argument, the compiler knows that 'f1' is not the actual name of the routine. To find the actual linker name, the caller chain will have to be traced to its beginning.
Only after posting my first response and reading Simon's reply to it did I realize that there were two separate issues: optional arguments and host association. I wrote my second response so that the host association issues could be exposed. Perhaps Simon did not care about host variables being hidden by local variables with the same name in his example, but I felt that this pitfall should be pointed out. |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|