Why does GCC not warn me when I forget to specify the return type of a interface function? For me this behavior seams unexpected. What do you say to this?
This is the test-program (uncoment Line 6 and it works as it should):
program returntest
implicit none
interface
function givehalf(Y)
double precision :: Y
!double precision :: givehalf !<-- Uncomment this line
end function givehalf
end interface
double precision :: temp
temp=givehalf(5.151515d0)
print*, 'result= ',temp
end program returntest
function givehalf(Y)
implicit none
double precision :: Y
double precision :: givehalf
print*, 'Y= ',Y
givehalf=Y/2.0d0
print*, 'return Y/2',givehalf
return
end function givehalf
The result is this:
user#bapf028dl:/media/disk> gfortran44 -Wall return-test.f90
user#bapf028dl:/media/disk> ./a.out
Y= 5.1515149999999998
return Y/2 2.5757574999999999
result= -1.0579199790954590
user#bapf028dl:/media/disk> ifort return-test.f90
user#bapf028dl:/media/disk> ./a.out
Y= 5.15151500000000
return Y/2 2.57575750000000
result= 2.57575750350952
edit: It is really a bug. It gives a type error in gfortran 4.6 and 4.7.
Also I would recommend you to use a module for your functions. You have only one place to change.
This is not a bug. The interface body inside an interface block forms a separate scope, so you should include an implicit none statement there to prevent yourself from making such errors. Without it the implicit typing rules are in effect, so the function is expected to return a real.
interface
function givehalf(Y)
implicit none !<-- now you should get an error during compilation
double precision :: Y
!double precision :: givehalf !<-- Uncomment this line
end function givehalf
end interface
Related
I am trying to create a generic function in Fortran based on the value to be returned, that is, depending on if the output of the function is to be assigned to a single precision real or to a double precision real. The code is:
MODULE kk_M
USE ISO_FORTRAN_ENV
IMPLICIT NONE
INTEGER, PARAMETER :: sp = REAL32
INTEGER, PARAMETER :: dp = REAL64
INTERFACE use_func
MODULE PROCEDURE use_sp_func
MODULE PROCEDURE use_dp_func
END INTERFACE use_func
INTERFACE use_sub
MODULE PROCEDURE use_sp_sub
MODULE PROCEDURE use_dp_sub
END INTERFACE use_sub
CONTAINS
FUNCTION use_sp_func() RESULT(res)
REAL(KIND=sp) :: res
res = 5._sp
END FUNCTION use_sp_func
FUNCTION use_dp_func() RESULT(res)
REAL(KIND=dp) :: res
res = 5._dp
END FUNCTION use_dp_func
SUBROUTINE use_sp_sub(res)
REAL(KIND=sp), INTENT(OUT) :: res
res = 5._sp
END SUBROUTINE use_sp_sub
SUBROUTINE use_dp_sub(res)
REAL(KIND=dp), INTENT(OUT) :: res
res = 5._dp
END SUBROUTINE use_dp_sub
END MODULE kk_M
PROGRAM kk
USE kk_M
IMPLICIT NONE
REAL(KIND=sp) :: num_sp
REAL(KIND=dp) :: num_dp
num_sp = use_func()
WRITE(*,*) num_sp
num_dp = use_func()
WRITE(*,*) num_dp
CALL use_sub(num_sp)
WRITE(*,*) num_sp
CALL use_sub(num_dp)
WRITE(*,*) num_dp
END PROGRAM kk
With the generic subroutines the code compiles and works, but when I add the generic functions it does not compile. I get the following error message with gfortran:
kk.f90:22:3:
FUNCTION use_sp_func() RESULT(res)
1
kk.f90:27:3:
FUNCTION use_dp_func() RESULT(res)
2
Error: Ambiguous interfaces in generic interface 'use_func' for ‘use_sp_func’ at (1) and ‘use_dp_func’ at (2)
kk.f90:46:7:
USE kk_M
1
Fatal Error: Can't open module file ‘kk_m.mod’ for reading at (1): No existe el archivo o el directorio
compilation terminated.
It looks like the compiler cannot distinguish between both functions based on the value to be returned. Is there some way to achieve this?
You cannot distinguish specific functions in a generic interface by their return value. There is no way how the compiler can see what return value type is to be used. A Fortran expression is always evaluated without the surrounding context. Fortran generic disambiguation is based by TKR (type, kind, rank) resolution only using the procedure arguments, not using the return value.
When you have
use_func()
there is no way for the compiler to know which of those two functions should be called. Even when it is used directly in an assignment
x = use_func()
it is evaluated separately. In general, function calls can appear in various complicated expressions. E.g. use_func(use_func()) + use_func(), which one would be which?
This is the reason why several intrinsic functions have another argument that specifies the return type. For example, the transfer() function has a second argument that specifies which type should be returned. Otherwise the compiler would not be able to find out.
Following the advice by Vladimir F, I had a look at the transfer intrisic function and added a mold parameter to my functions to set the return type.
If any input argument to the functions were real they could be used to set the return type as High Performace Mark stated, but since this is not my case I finally used the mold variable.
Now it compiles and work. The code is:
MODULE kk_M
USE ISO_FORTRAN_ENV
IMPLICIT NONE
INTEGER, PARAMETER :: sp = REAL32
INTEGER, PARAMETER :: dp = REAL64
INTERFACE use_func
MODULE PROCEDURE use_sp_func
MODULE PROCEDURE use_dp_func
END INTERFACE use_func
INTERFACE use_sub
MODULE PROCEDURE use_sp_sub
MODULE PROCEDURE use_dp_sub
END INTERFACE use_sub
CONTAINS
FUNCTION use_sp_func(mold) RESULT(res)
REAL(KIND=sp),INTENT(IN) :: mold
REAL(KIND=sp) :: res
IF (.FALSE.) res = mold !To avoid compilation warning about unused variable
res = 5._sp
END FUNCTION use_sp_func
FUNCTION use_dp_func(mold) RESULT(res)
REAL(KIND=dp),INTENT(IN) :: mold
REAL(KIND=dp) :: res
IF (.FALSE.) res = mold !To avoid compilation warning about unused variable
res = 5._dp
END FUNCTION use_dp_func
SUBROUTINE use_sp_sub(res)
REAL(KIND=sp), INTENT(OUT) :: res
res = 5._sp
END SUBROUTINE use_sp_sub
SUBROUTINE use_dp_sub(res)
REAL(KIND=dp), INTENT(OUT) :: res
res = 5._dp
END SUBROUTINE use_dp_sub
END MODULE kk_M
PROGRAM kk
USE kk_M
IMPLICIT NONE
REAL(KIND=sp) :: num_sp
REAL(KIND=dp) :: num_dp
num_sp = use_func(1._sp)
WRITE(*,*) num_sp
num_dp = use_func(1._dp)
WRITE(*,*) num_dp
CALL use_sub(num_sp)
WRITE(*,*) num_sp
CALL use_sub(num_dp)
WRITE(*,*) num_dp
END PROGRAM kk
For some use I need to define a function inside another function inside a fortran module.
A sample code for easy comprehension is
module func
implicit none
contains
real function f(x,y)
real x,y,g
real function g(r)
real r
g=r
end function g
f=x*g(y)
end function f
end module func
use func
implicit none
write(*,*) f(1.0,1.0)
end
This is giving lots of errors in gfortran like unexpected data declaration, expected end function f, not g....etc.
What is the correct way of defining a function inside another function in fortran?
You use an internal subprogram, see below. Note internal subprograms themselves can not contain internal subprograms.
ian#eris:~/work/stack$ cat contained.f90
Module func
Implicit None
Contains
Real Function f(x,y)
! Interface explicit so don't need to declare g
Real x,y
f=x*g(y)
Contains
Real Function g(r)
Real r
g=r
End Function g
End Function f
End Module func
Program testit
Use func
Implicit None
Write(*,*) f(1.0,1.0)
End Program testit
ian#eris:~/work/stack$ gfortran-8 -std=f2008 -Wall -Wextra -fcheck=all -O -g contained.f90
ian#eris:~/work/stack$ ./a.out
1.00000000
ian#eris:~/work/stack$
The question is why i get an error saying the integer charlen is a real when i pass it as the length definition of a character elemental function. To be more specific, the folowing MWE works:
program chararr
implicit none
!!
integer,parameter :: charlen = 20
!!
interface
character(len=20) elemental function adjR(a)
character(len=*),intent(in) :: a
end function
end interface
!!
character(charlen) :: test(3), testR(3)
test = ["hej", "hoj", "haj"]
testR = adjR(test)
print*, test
print*, testR
end program
character(20) elemental function adjR(a)
character(len=*),intent(in) :: a
adjR = adjustr(a)
end function
but the line integer,parameter :: charlen = 20 does nothing. When i change the function and interface definitions like this
character(len=charlen) elemental function adjR(a)
i get the following error:
charmin.f90:7:14:
character(len=charlen) elemental function adjR(a)
1
Error: Expression at (1) must be of INTEGER type, found REAL
UPDATE
The solution of Alexander is in code:
charmin.f90:
program chararr
use char_mod, only: charlen, adjR
implicit none
!!
!interface
!character(30) elemental function adjR(a)
!character(len=*),intent(in) :: a
!end function
!end interface
!!!
character(charlen) :: test(3), testR(3)
test = ["hej", "hoj", "haj"]
testR = adjR(test)
print*, test
print*, testR
print*, charlen !!! it is here
end program
char_mod.f90:
module char_mod
implicit none
integer,parameter :: charlen = 30
private
public charlen, adjR
contains
character(charlen) elemental function adjR(a)
implicit none
character(len=*),intent(in) :: a
adjR = adjustr(a)
end function
end module
To compile:
gfortran -c char_mod.f90
gfortran charmin.f90 char_mod.f90 -o program
charlen is defined in the scope of the program, but the function adjR is outside that scope. Consequently, charlen is not accessible, and since the function does not have implicit none defined, it is interpreted as a real variable.
One solution to this would be to put adjR in a module, and make charlen a module variable.
I created a fortran 90 program that I used on a linux machine and compiled using gfortran. It worked fine on the linux machine with gfortran but provides the error
error 327 - In the INTERFACE to SECANTMETHOD (from MODULE SECMETH), the ninth dummy argument (F) was of type REAL(KIND=2) FUNCTION, whereas the actual argument is of type REAL(KIND=2)
when using the Plato compiler (FTN95). Does anyone know how I would need to change my code to work in Plato? I tried to read up on this error and there was some mention of pointers but from what I tried that did not work. I have figured out some workarounds but they make it so that the subroutine can no longer accept any function as an argument - which is pretty much useless. Any help would be greatly appreciated. My code is below.
!--! A module to define a real number precision.
module types
integer, parameter :: dp=selected_real_kind(15)
end module types
module secFuncs
contains
function colebrookWhite(T)
use types
real(dp) :: colebrookWhite
real(dp), intent(in) :: T
colebrookwhite=25-T**2
return
end function colebrookWhite
end module secFuncs
module secMeth
contains
subroutine secantMethod(xolder,xold,xnew,epsi1,epsi2,maxit,exitFlag,numit,f)
use types
use secFuncs
implicit none
interface
function f(T)
use types
real(dp) :: f
real(dp), intent(in) :: T
end function f
end interface
real(dp), intent(in) :: epsi1, epsi2
real(dp), intent(inout) :: xolder, xold
real(dp), intent(out) :: xnew
integer, intent(in) :: maxit
integer, intent(out) :: numit, exitFlag
real(dp) :: fxold, fxolder, fxnew
integer :: i
fxolder = f(xolder)
fxold = f(xold)
i = 0
do
i = i + 1
xnew = xold - fxold*(xold-xolder)/(fxold-fxolder)
fxnew = f(xnew)
if (i == maxit) then
exitFlag = 1
numit = i
return
else if (abs(fxnew) < epsi1) then
exitFlag = 2
numit = i
return
else if (abs(xnew - xold) < epsi2) then
exitFlag = 3
numit = i
return
end if
xolder = xold
xold = xnew
fxolder = fxold
fxold = fxnew
end do
end subroutine secantMethod
end module secMeth
program secantRoots
use types
use secMeth
use secFuncs
implicit none
real(dp) :: x1, x2, xfinal, epsi1, epsi2
integer :: ioerror, maxit, numit, exitFlag
do
write(*,'(A)',advance="no")"Please enter two initial root estimates, 2epsi's, and maxit: "
read(*,*,iostat=ioerror) x1, x2, epsi1, epsi2, maxit
if (ioerror /= 0) then
write(*,*)"Invalid input."
else
exit
end if
end do
call secantMethod(x1,x2,xfinal,epsi1,epsi2,maxit,exitFlag,numit,colebrookWhite)
if (exitFlag == 1) then
write(*,*)"The maximum number of iterations was reached."
else if (exitFlag == 2) then
write(*,'(a,f5.3,a,i3,a)')"The root is ", xfinal, ", which was reached in ", numit, " iterations."
else if (exitFlag == 3) then
write(*,'(a,i3,a)')"There is slow or no progress at ", numit, " iterations."
end if
end program secantRoots
Current gfortran detects the error in the call to the secantMethod procedure, where you have parentheses, but no argument list, following the colebrookWhite function name.
If you want to pass a function as an argument (as opposed to the result of evaluating a function), which is what you want to do here, you do not follow the function name with a parenthesis pair.
call secantMethod(x1,x2,xfinal,epsi1,epsi2,maxit,exitFlag,numit,colebrookWhite )
! ^
I ended up just switching from Plato to Geany IDE (I actually like Geany WAY better now that I've used it for a couple hours), setting up gfortran with Geany, and the code works with that setup. I'm guessing the reason I'm getting the error with Plato is that its compiler is actually a fortran95 compiler while gfortran is a fortran90 compiler. It took a while to get everything working but once I downloaded mingw-w64 for gfortran and set the path user (not system) environment variable to the correct location everything works great. I would still be interested in seeing if there is a way to get the code working with the FTN95 compiler, but in the end I'm still sticking with gfortran and Geany.
I guess I could easily use some help here, since I'm messing around with some fortran 2003 but can't seem to understand how to do things really.
The fact is that I need to write a fortran code that declares, inside a module, a new data type
that has as one of its members a pointer to a real function. Something like
module new_mod
type my_type
real*8 :: a, b
(here something that declares a real*8 function), pointer :: ptr
end type my_type
end module_new
module funcs
real*8 function function1(x)
real*8 :: x
function1 = x*x
end function function1
real*8 function function2(x)
real*8 :: x
function2 = x*x
end function function2
end module funcs
then in the main program I would like to have something like
program my_prog
use module_new
use module_funcs
implicit none
real*8 :: y, z
type(my_type) :: atom
...
atom%ptr => function1
y = atom%ptr(x)
...
atom%ptr => function2
z = atom%ptr(x)
end program my_prog
while
so the main idea is that module_new contains a type that has a pointer to a real
function. This pointer in th eobjects of the new type I must be able to point to different functions in the main program.
I have seen one can do similar things with abstract interfaces and such, but honestly, I'm in a mess here. If someone could help, I'll appreciate that.
Cheers...
Well, that is not really the type of question you would send to stackoverflow, but actually your code needs only a "slight improvement" (by appropriate definition of slight) to work:
module accuracy
implicit none
integer, parameter :: dp = kind(1.0d0)
end module accuracy
module typedef
use accuracy
implicit none
type :: mytype
real(dp) :: aa, bb
procedure(myinterface), pointer, nopass :: myfunc
end type mytype
abstract interface
function myinterface(xx)
import :: dp
real(dp), intent(in) :: xx
real(dp) :: myinterface
end function myinterface
end interface
end module typedef
module funcs
use accuracy
implicit none
contains
function func1(xx)
real(dp), intent(in) :: xx
real(dp) :: func1
func1 = xx
end function func1
function func2(xx)
real(dp), intent(in) :: xx
real(dp) :: func2
func2 = 2.0_dp * xx
end function func2
end module funcs
program test
use accuracy
use typedef
use funcs
implicit none
real(dp) :: xx
type(mytype) :: atom
xx = 12.0_dp
atom%myfunc => func1
print *, atom%myfunc(xx)
atom%myfunc => func2
print *, atom%myfunc(xx)
end program test
There are several things to be worth to mentioned:
You should use one global parameter for your accuracy (see module accuracy) and forget about real*8.
Your procedure pointer in your derived type needs an interface, which is provided within the following abstract interface block (see 'abstract interfaces' in a good F2003 book).
You need the nopass option for the procedure pointer in the derived type as otherwise Fortran will assume that the first parameter passed to the function/subroutine is the derived type itself (see 'type bound procedures' in a good F2003 book).
Finally, although rather obvious: You should definitely read a book about the Fortran 2003 features if you are serious about using them in a production code.