I'm beginning with Fortran 2008 and I'm struggling with OOP greatly. It seems, that there are very few materials, which explain a very basic OOP concepts in 2008 language standard.
I've found information about inheritance, but I was unable to find any info about polymorphism.
So if I wanted to overload a function in C++, I can do it like this (example from Wikipedia):
// volume of a cube
int volume(const int s)
{
return s*s*s;
}
// volume of a cylinder
double volume(const double r, const int h)
{
return 3.1415926*r*r*static_cast<double>(h);
}
// volume of a cuboid
long volume(const long l, const int b, const int h)
{
return l*b*h;
}
But, how am I supposed to do the same thing in Fortran 2008?
The idea of overloading as given in the C++ examples has an implementation in Fortran, dating back to the generics of Fortran 90.
Given a set of specific procedures a generic identifier may be used to identify this set. In this answer I'll give a very high-level introduction to this concept. There are a lot of subtleties which may require further reading/questions to address.
Unlike the C++ example, our Fortran specific procedures need to be named separately. Let's have the two functions (third can be added mutatis mutandis)
integer function volume_cube(s)
integer, intent(in) :: s
...
end function volume_cube
double precision function volume_cylinder(r, h)
double precision, intent(in) :: r
integer, intent(in) :: h
...
end function volume_cylinder
We can then add a generic interface for something called volume:
interface volume
procedure volume_cube, volume_cylinder
end interface
We can then reference the generic volume and the compiler will determine which specific function to use.
There is much more to learn about generics, including what else they offer beyond this simple overloading. One should also understand how specific procedures are resolved (simple in this case, not so in others) and the restrictions on which specific procedures may be lumped together. As you use generics problematic cases are likely to have particular questions. I answer here only as I couldn't see an introductory question and I don't attempt to address the many varied difficulties or values.
Complete example
module mod
private
interface volume
module procedure volume_cube, volume_cylinder
end interface volume
public volume
contains
integer function volume_cube(s)
integer, intent(in) :: s
volume_cube = s**3
end function volume_cube
double precision function volume_cylinder(r, h)
double precision, intent(in) :: r
integer, intent(in) :: h
volume_cylinder = 3.1415926d0*r**2*h
end function volume_cylinder
end module mod
use mod
print*, volume(2), volume(2d0,4)
end
expanding Fancescalus example:
module Pablo_Dali
private
interface volume_Cube
module procedure volume_cube_Int, volume_cube_Float, Colume_cube_Double
!add in 8, 16, and 64 bit ints... and complex??
end interface volume
public volume_Cube
contains
integer function volume_cube_Int(s)
integer, intent(in) :: s
volume_cube_Int = s**3
end function volume_cube_int
float function volume_cube_Float(s)
float, intent(in) :: s
volume_cube_float = s**3
end function volume_cube_Float
integer function volume_cube_Double(s)
DOUBLE, intent(in) :: s
volume_cube_Double = s**3
end function volume_cube_Double
end module Pablo_Dali
then the code:
PROGRAM Cube_Volume
USE Pablo_Dali
IMPLICIT NONE
INTEGER :: I_Side, I_Volume
FLOAT :: F_Side, F_Volume
DOUBLE :: D_Side, D_Volume
I_Side = 1
F_Side = 1.0E0
D_Side = 1.0D0
WRITE(*,*)'[INT] ',I_Side,' cubed=', volume_cube(I_Side)
WRITE(*,*)'[FLOAT] ',F_Side,' cubed=', volume_cube(F_Side)
WRITE(*,*)'[DOUBLE] ',D_Side,' cubed=', volume_cube(D_Side)
END PROGRAM Cube_Volume
Related
I have a C function that uses structures. I developed a Fortran Wrapper which calls the C function. Both libraries are built successfully. I have passed the variables form the PSCAD model and run the case. The PSCAD model is throwing the error.
Error Message:
Type Id Component Namespace Description
dll_df FORTRA~1.LIB(dlltestx.obj) : error LNK2019: unresolved external symbol _test_cfun referenced in function _AUX_CFUN
C-Code:
// This is an example of an exported variable
typedef struct _goose_c
{
int in1;
float in2;
}goose_c;
__declspec(dllexport) void test_cfunc(goose_c *V, double *out1)
{
//*out1 = (*V).in1 + (*V).in2;
*out1 = V->in1 + V->in2;
}
Fortran Wrapper Code:
SUBROUTINE AUX_CFUN(ip1, ip2, out1)
use, intrinsic :: iso_c_binding
implicit none
integer, intent(in) :: ip1
real, intent(in) :: ip2
real, intent(out) :: out1
type, bind(C) :: goose_t
integer(c_int) :: in1
real(c_double) :: in2
end type goose_t
type(goose_t) :: goose_f
! Fortran 90 interface to a C procedure
INTERFACE
SUBROUTINE TEST_CFUN (goose_f,out1) bind (C)
use iso_c_binding
import :: goose_t
type(goose_t), intent (in) :: goose_f
real(c_double), intent (out) :: out1
END SUBROUTINE TEST_CFUN
END INTERFACE
goose_f%in1 = ip1
goose_f%in2 = ip2
! call of the C procedure
CALL TEST_CFUN(goose_f,out1)
RETURN
END SUBROUTINE AUX_CFUN
The bind (C) clause in the interface should be completed with the exact (including the correct case) C name of the function you want to interface; so in your example it should read bind (C, name='test_cfunc'). The Fortran name associated to the C function (TEST_CFUN in your example) can be in principle different, it's up to you to decide whether this is a good idea or not, and it is used in your fortran program with the usual fortran rules, so it is case-insensitive.
I am new to Fortran and I am trying on the common block. My code is simple
program main
implicit double precision (p)
real * 8 :: x, y
common /yvalue/ y
x = 3d0
y = 3d0
print *, power(x)
end program main
function power(x)
implicit none
real * 8 :: power
real * 8 :: x, y
common /yvalue/ y
power = x ** y
end function power
It works but if I comment out the second line, which implicitly declares variables starting with p to be double precision, the compiler complains the following
Error: Return type mismatch of function ‘power’ at (1) (REAL(4)/REAL(8))
I do get the point that the return value power is by default a single precision variable, but why declaring power as double precision in the function is not enough? And why writing real * 8 power in main would not work either?
When a procedure (function or subroutine) that you are trying to invoke in your code lays outside the body of your program and also is not part of any module, it's named an external function (or subroutine).
Fortran is a statically-typed language, so the types of all variables and functions must be known at compile-time. So, if you want to reference an external function in your program, there must be a way for the program to know its return type. You have 3 (bad) options for this, and I'll list them, starting from the worst:
WORST: Rely on an implicit-typing rule that happens to match the return type of the external function with the type associated with its identifier in the caller (as you did in your sample).
Why you shouldn't do that? Because it is cancer. It makes the meaning of the code obscure, you can't know what this name reference to. It may even look just like an array variable in some circumstances, instead of a function. Also, the compiler doesn't check argument conformance in this case, so if you don't have specific compiler options turned on, the code will fail at runtime, or worse, will give wrong results. Moreover, implicit-typing is very very rarely useful these days, most of the time it's an ask for trouble. Always use implicit none!
As you noted, by the default rules of implicit-typing, any variable with a name starting with p will be default real type (in your compiler, it is real(4)). As you declared the function result as real*8, that your compiler interpret as real(8) (see final note), the error arises.
BAD: Declare the function's name and type in the caller's specification area.
You'd do that just like you'd declare a variable, like this:
program main
implicit none
real*8 :: x, y, power
By the way, the attribute external may be applied to external procedures like yours. More than giving some properties to the procedure (can be passed as an actual argument, disambiguation from intrinsic procedures), it would make the origin of the identifier clearer.
program main
implicit none
real*8 :: x, y, power
external :: power
Why you shouldn't do that? There is no argument checking by the compiler either. This severely limits your options for communicating to external functions: the arguments cannot be assumed-shape, assumed-rank, polymorphic, parameterized, coarray, or be declared on the callee side as allocatable, optional, pointer, target, asynchronous, volatile or value; the return type cannot be an array, or pointer, or allocatable; the function cannot be passed as argument, be elemental and, if pure, can't be used in such contexts. And the reason for all this is the lack of an explicit interface.
ACCEPTABLE: Specify an interface for your external function in the caller.
Like this:
program main
implicit none
interface
real*8 function power(y)
real*8 :: y
end function
end interface
This way, the compiler is able to know all details of declaration and all the restrictions I mentioned won't apply. Total freedom and code clarity!
Why you shouldn't do that? Because there is a better way, that is using modules! Well, it's totally ok to do this in contexts were you can't go for modules, e.g. when working with already existent large old code. The downside is that, you have almost the same code in two different places, and they must always match.
Bonus: BETTER: Use modules.
program main
use :: aux_module
implicit none
real*8 :: x, y
common /yvalue/ y
x = 3d0
y = 3d0
print *, power(x)
end
module aux_module
implicit none
contains
function power(x)
real*8 :: power
real*8 :: x, y
common /yvalue/ y
power = x ** y
end
end
Why you should definitely do that? Because with modules, interfaces are automatically and implicitly available (less code duplication, no restrictions); modules can be recompiled separately and updated without breaking code. Also, you can declare shared variables in the scope of the module and avoid using common declarations. An even better version of your code would be:
program main
use aux_module
implicit none
real*8 :: x
x = 3d0
y = 3d0
print *, power(x)
end
module aux_module
implicit none
real*8 :: y
contains
function power(x)
real*8 :: power
real*8 :: x
power = x ** y
end
end
There is even the option to include your functions directly into your program, after contains. This is recommended only if you don't plan to reuse this function in other program units. #IanBush's answer covers this case.
Final note: take a look on this answer to see why the syntax real*8 is non-standard and should be avoided.
As stated in the comments simply declaring the function in not only its own scope but also the scope that it is called will solve your problem. However I also want to discourage you from using common, implicit typing, and the completely non-standard real*8. As such here is a version of your program in a more modern dialect
ian#eris:~/work/stackoverflow$ cat power.f90
Program power_program
Implicit None
Integer, Parameter :: wp = Selected_real_kind( 14, 70 )
Real( wp ) :: x, y
x = 3.0_wp
y = 3.0_wp
! Return type and kind of the function power in scope
! due to the implicit interface
Write( *, '( 3( a, 1x, f0.6, 1x ) )' ) &
'x =', x, 'y = ', y, 'x**y = ', power( x, y )
Contains
Pure Function power( x, y ) Result( r )
Real( wp ) :: r
Real( wp ), Intent( In ) :: x
Real( wp ), Intent( In ) :: y
r = x ** y
End Function power
End Program power_program
ian#eris:~/work/stackoverflow$ gfortran -std=f2003 -Wall -Wextra -O power.f90
ian#eris:~/work/stackoverflow$ ./a.out
x = 3.000000 y = 3.000000 x**y = 27.000000
ian#eris:~/work/stackoverflow$
I want to combine C++ and Fortran together. My Fortran code will use a C++ function and C++ function changes variables of Fortran and sends them back. The C++ function is built with other C++ codes, e.g. the C++ function will use some sub-function in other .cpp file. I make the Fortran code with ifort and I added that C++ function as one object file, test.o in my Fortran makefile. I also put every needed C++ .o file(support test.o) in makefile. It shows the error
#6633, "The type of the actual argument differs from the type of the dummy argument".
Here is the code.
Fortran code
use, intrinsic :: ISO_C_BINDING, only: C_INT, C_DOUBLE
implicit double precision(a-h,o-z),integer(i-n)
Interface
integer (C_INT) function SolveBIE_(x, y, aa, m) BIND(C, NAME='SolveBIE_')
use, intrinsic :: ISO_C_BINDING
implicit none
type (C_PTR), value :: x
type (C_PTR), value :: y
type (C_PTR), value :: aa
integer (C_INT), value :: m
end function SolveBIE_
end Interface
integer (C_INT) :: m
real (C_DOUBLE), ALLOCATABLE, DIMENSION(:,:), target :: x
real (C_DOUBLE), ALLOCATABLE, DIMENSION(:,:), target :: y
real (C_DOUBLE), ALLOCATABLE, DIMENSION(:,:), target :: aa
ALLOCATE(x(0:MAXLEN,MAXINTERFACES))
ALLOCATE(y(0:MAXLEN,MAXINTERFACES))
ALLOCATE(aa(0:MAXLEN,MAXINTERFACES))
My Fortran code run
mm = SolveBIE_(x(1,1),y(1,1),aa(1,1),m)
Using the C++ code and where the error is from, on x, y, aa
I use x(1,1) instead of x, because if using x, then there is another error
#6634,"the shape matching rules of actual arguments and dummy arguments have been violated"`
I don't understand why it should be x(1,1). Why is this working, not x?
My C++ code
#ifdef __cplusplus
extern "C" {
#endif
int solveBIE_(double *ini_bdry_x, double *ini_bdry_y, double *ini_bdry_um, int *fM)
{
double(*bdry_node)[2] = new double[M1][2];
for (int k = 0; k < M; k++) {
bdry_node[k+1][0] = ini_bdry_x[k+1];
bdry_node[k+1][1] = ini_bdry_y[k+1];
bdry_theta[k+1] = Atan(ini_bdry_x[k+1], ini_bdry_y[k+1]);}
... some functions in other .cpp file
The way your interface is written, you have to construct a C_PTR to array x and pass that as the first argument:
use, intrinsic :: ISO_C_BINDING, only: C_INT, C_DOUBLE, C_PTR, C_LOC
! ...
type(C_PTR) PTRx
! ...
PTRx = C_LOC(x(LBOUND(x,1),LBOUND(x,2)))
! ...
mm = solveBIE_(PTRx, PTRy, PTRaa, m)
As shown above, you would have to fix the next two arguments as well. But you need to rewrite the interface for argument fM because as matters stand, Fortran will pass an integer by value whereas C++ is expecting a pointer. Given that, I would rewrite the interface completely, using the names given for the arguments in the C++ function and passing everything by reference. Names for dummy arguments are potentially visible in Fortran, so it's useful for them to be meaningful. In the following I assume that fM points to a scalar in the callee:
Interface
function SolveBIE_(ini_bdry_x, ini_bdry_y, ini_bdry_um, fM) &
BIND(C, NAME='SolveBIE_')
import
implicit none
integer(C_INT) SolveBIE_
real(C_DOUBLE) :: ini_bdry_x(*)
real(C_DOUBLE) :: ini_bdry_y(*)
real(C_DOUBLE) :: ini_bdry_um(*)
integer (C_INT) :: fM
end function SolveBIE_
end Interface
Then later on you can invoke it more or less normally as
mm = SolveBIE_(x,y,aa,m)
Note that x(1,1) was wrong because LBOUND(x,1) = 0, not 1!
Is there an equivalent for the 'a' format specifier known from C in Fortran?
C Example:
printf("%a\n",43.1e6); // 0x1.48d3bp+25
Exporting floating point numbers in hexadecimal format prevents rounding errors. While the rounding errors are usually negligible, it is still advantageous to be able to restore a saved value exactly. Note, that the hexadecimal representation produced by printf is portable and human readable.
How can I export and parse floating point numbers in Fortran like I do in C using the 'a' specifier?
If you want to have full precision, the best way is to use unformatted files, such as this:
program main
real :: r
integer :: i
r = -4*atan(1.)
open(20,access="stream")
write (20) r
close(20)
end program main
(I used stream access, which is new to Fortran 2003, because
it is usually less confusing than normal unformatted access). You can then use, for example, od -t x1 fort.20 to look at this as a hex dump.
You can also use TRANSFER to copy the bit pattern to an integer and then use the Z edit descriptor.
If you really want to mimic the %a specifier, you'll have to roll your own. Most machines now use IEEE format. Use TRANSFER for copying the pattern to an integer, then pick that apart using IAND (and multiplications or divisions by powers of two for shifting).
Another option would be to let the C library do your work for you and interface via C binding. This rather depends on a modern compiler (some F2003 features used).
module x
use, intrinsic :: iso_c_binding
private
public :: a_fmt
interface
subroutine doit(a, dest, n) bind(C)
import
real(kind=c_double), value :: a
character(kind=c_char), intent(out) :: dest(*)
integer, value :: n
end subroutine doit
end interface
interface a_fmt
module procedure a_fmt_float, a_fmt_double
end interface a_fmt
contains
function a_fmt_float(a) result(res)
real(kind=c_float), intent(in) :: a
character(len=:), allocatable :: res
res = a_fmt_double (real(a, kind=c_double))
end function a_fmt_float
function a_fmt_double(a) result(res)
real(kind=c_double), intent(in) :: a
character(len=:), allocatable :: res
character(len=30) :: dest
integer :: n
call doit (a, dest, len(dest))
n = index(dest, achar(0))
res = dest(1:n)
end function a_fmt_double
end module x
program main
use x
implicit none
double precision :: r
integer :: i
r = -1./3.d0
do i=1,1030
print *,a_fmt(r)
r = - r * 2.0
end do
end program main
#include <stdio.h>
void doit (double a, char *dest, int n)
{
snprintf(dest, n-1, "%a", a);
}
I'm new in Fortran. what's the problem with this simple code?
program combinatorial
Implicit none
integer :: m, n, Fact
integer :: Com
Write (*,*) 'inter 2 number for m and n'
Read (*,*) m,n
Com = Fact (m)/(Fact(n)*Fact(m-n))
Contains
integer Function Fact(t)
Implicit none
Integer, intent(IN) :: t
integer :: i, Ans
Ans = 1
Do i=1, t
Ans=Ans * i
End do
Fact = Ans
End Function Fact
End program combinatorial
The error that i encounter is :
combinatorial.f90(10): error #6626: The name of the internal procedure conflicts with a name in the encompassing scoping unit. [FACT]
integer Function Fact(t)
-------------------------^
compilation aborted for combinatorial.f90 (code 1)
Since Fact is contained within the program the compiler will generate an interface to it automatically. By also declaring an integer thing called Fact you're giving the compiler conflicting instructions and it don't like that. Just drop Fact from the line
integer :: m, n, Fact
The encompassing scoping unit referred to by the compiler is the program which contains (or encompasses) the function.
And, as an aside, you don't need to use the variable Ans in your definition of the function. You could simply write
integer Function Fact(t)
Implicit none
Integer, intent(IN) :: t
integer :: i
Fact = 1
Do i=1, t
Fact = Fact * i
End do
End Function Fact
Unless you use a result clause on the function statement the compiler will behave as if it creates a variable of the same name as the function for returning the function's result.