Truncate the number of variables in a Fortran 95 function - fortran

Suppose that I want to pass a function to another function via f1(f2(k, g, x), other, junk) (f1 is defined as f1(func, other, junk) and it involves expressions like func(other).) Further suppose that both of these functions are contained in a third function f3(k, g). By calling f3(k, g) with some values of k and g, f2 isn't really a function of three variables anymore, is it? It's only a function of x since k and g are now constants. So what I want to know is whether or not there's somehow a way of saying "look, f2, you didn't know what k and g were when I defined you, but now you do since I told f3 what they were, so you can just consider yourself as a function of x, so when I pass you to f1, it sees and uses a function of only one variable."

What I think you are looking for is sometimes called a "functor/function object" or lambda expression - the ability to wrap a procedure with a number of arguments up in a way that it can be called with fewer arguments (the missing arguments being specified via other means).
In Fortran 77 this was typically approximated by passing the "missing" arguments through behind the scenes in a common block. Fortran 90/95's varied that by letting you use module variables. Both these approaches have the downside that only a single instance of the wrapped procedure can be extant at the one time, though the use of modules over common blocks is a vastly superior option for other reasons.
Fortran 2003 introduces other options - using derived types and type extension. This requires changes to the code of f1 - instead of having a dummy procedure argument the function takes a polymorphic argument, the declared type of which has a binding that has the interface similar to the former argument of f1 but with a passed object. The missing arguments then become components in extensions of that declared type. This approach brings with it a vast increase in flexibility and capability, not the least of which is that multiple instances of the wrapped procedure can then be extant at any one time, at the cost of some verbosity.
Fortran 2008 introduces another option using internal procedures, with the missing arguments passed via host association from a host procedure to the internal procedure. (This approach was not available in previous standards because internal procedures were not permitted to be passed as actual procedure arguments). Multiple instances of the wrapped procedure can be extant through the use of procedure pointers.
Examples for the four different approaches attached. Note that the other and junk entities have not been declared in any of the examples of the F3 procedure, and there may be some other omissions (or what I would consider very poor programming style) for the sake of the example. Further, note that the four approaches differ greatly in terms of the flexibility and robustness of the code (likelihood that programmer error being caught, etc).
C*******************************************************************************
C FORTRAN 77
FUNCTION F1(FUNC,OTHER,JUNK)
F1=FUNC(OTHER)+JUNK
END FUNCTION F1
C
FUNCTION F2(K,G,X)
F2=K+G+X
END FUNCTION F2
C
FUNCTION F3(K,G)
COMMON /F2COM/KC,GC
KC=K
GC=G
F3=F1(F2WRAP,OTHER,JUNK)
END FUNCTION F3
C
FUNCTION F2WRAP(X)
COMMON /F2COM/KC,GC
F2WRAP=F2(KC,GC,X)
END FUNCTION F2WRAP
!*******************************************************************************
! Fortran 90/95
MODULE m1990
IMPLICIT NONE
INTEGER :: km
REAL :: gm
CONTAINS
FUNCTION F2Wrap(x)
REAL :: x
!****
! F2 unchanged from F77, though good practice would be to make
! it (and F1 and F3) module procedures.
! ensure it had an explicit interface here.
F2Wrap = F2(km,gm,x)
END FUNCTION F2Wrap
END MODULE m1990
FUNCTION F3(k,g)
USE m1990
IMPLICIT NONE
INTEGER :: k
REAL :: g, F3
!****
km = k
gm = g
! F1 unchanged from F77.
F3=F1(F2Wrap, other, junk)
END FUNCTION F3
!*******************************************************************************
! Fortran 2003
MODULE m2003
IMPLICIT NONE
TYPE Functor
CONTAINS
PROCEDURE(fun_intf), DEFERRED :: fun
END TYPE Functor
ABSTRACT INTERFACE
FUNCTION fun_intf(f,x)
IMPLICIT NONE
IMPORT :: Functor
CLASS(Functor), INTENT(IN) :: f
REAL :: x, fun_intf
END FUNCTION fun_intf
END INTERFACE
TYPE F2Functor
INTEGER :: k
REAL : g
CONTAINS
PROCEDURE :: fun => F2_wrap
END TYPE F2Functor
CONTAINS
FUNCTION F2_wrap(f,x)
CLASS(F2Functor), INTENT(IN) :: f
REAL :: F2_wrap, x
! F2 unchanged from F77
F2_wrap = F2(f%k, f%g, x)
END FUNCTION f2_wrap
! F1 modified. Now takes a polymorphic argument in-place of the
! dummy procedure - explicit interface REQUIRED.
FUNCTION F1(f, other, junk)
CLASS(Functor), INTENT(IN) :: f
REAL :: F1, other
INTEGER :: junk
F1 = f%fun(other) + junk
END FUNCTION
END MODULE m2003
! Good practice would make this a module procedure.
FUNCTION f3(k,g)
USE m2003
IMPLICIT NONE
TYPE(F2Functor) :: f
REAL F3, g
INTEGER :: k
!****
f%k = k
f%g = g
F3 = F1(f, other, junk)
END FUNCTION f3
!*******************************************************************************
! Fortran 2008 (use of procedure pointers not illustrated).
! Should be a module proc, etc...
FUNCTION F3(k,g)
REAL :: F3, g
INTEGER :: k
INTEGER :: k_host
REAL :: g_host
k_host = k
g_host = g
! F1 unchanged from F77 (though good practice is..., etc)
F3 = F1(F2Wrap, other, junk)
CONTAINS
FUNCTION F2Wrap(x)
REAL :: x, F2Wrap
! F2 unchanged from F77.
F2Wrap = F2(k_host, g_host, x)
END FUNCTION F2Wrap
END FUNCTION F3

Supposing that I am interpreting this correctly, then yes.
program func_test
integer :: a, b
a = 4
b = 3
print *,f3(a,b)
print *,f3(b,a)
contains
function f3(k,g)
integer :: k, g, x, f3
x = 2
f3 = f1(f2(k,g,x), 3, 13)
end function f3
function f2(k, g, x)
integer :: k, g, x, f2
f2 = k+g*x
end function f2
function f1(func, other, junk)
integer :: func, other, junk
f1 = func + other*junk
end function f1
end program func_test
Unless I am mistaken, f2(k,g,x) in this example will be evaluated and then sent to f1 as an integer. If you wanted f2 to be called from f1, then you would also have to pass the arguments k, g, and x from f3 to f1.

Related

how to get type name in Fortran

How can I get a unique name of a variable type in Fortran? An ideal case is shown below:
for the case
real::a
type(some)::x
I want to implement some function f(x) so that
f(a) = "real"
f(x) = "some"
The return value of f need not be a string, other cases, a unique integer for instance, is OK. Is such a built-in function exist?
No, such capability does not exist in Fortran. Some programming languages do have this (e.g. C++, it has almost anything someone can invent and some more https://en.cppreference.com/w/cpp/types/type_info/name but do note the disclaimers about uniqueness and mangling).
You can make a generic function for some limited set of types yourself
interface type_name
procedure type_name_real
procedure type_name_some
end interface
function type_name_real(o) result(res)
character(:), allocatable :: res
real, intent(in) :: o
res = "real"
end function
function type_name_some(o) result(res)
character(:), allocatable :: res
type(some), intent(in) :: o
res = "some"
end function
This obviously concerns the declared type and non-polymorphic entities. But your question did not show any polymorphism.

Accessing pointer to a polymorphic value with C_PTR

I have a Fortran function which compiled with previous versions of Intel Fortran Compiler (ifort), but is rejected by more recent versions (2021.6.0), and I hope to fix it. This function accepts a class(*), and passes its address and length to a C function:
!> Send an arbitrary scalar object.
function SendObject(my,obj) result(ok)
use, intrinsic :: iso_c_binding
implicit none
class(Socket) :: my
class(*), target, intent(in) :: obj
type(c_ptr) :: ptr
integer(c_size_t) :: len
ptr = c_loc(obj)
len = c_sizeof(obj)
ok = my%SendData(ptr,len)
end function
ifort now emits an error:
error #9023: The argument to C_LOC must not be polymorphic. [OBJ]
ptr = c_loc(obj)
While this function is polymorphic, in practice it is used only for a few simple structs containing scalars.
What is the best way to get this function "working" again, as well as it worked with previous compilers? I just need to get a C pointer to obj. Thanks for any help!

Undestanding c_ptr in fortran [duplicate]

I have a Fortran DLL which is called from a C program, and one of my procedures needs periodically to call a callback function which is supplied by the C program. I currently have it working well in its 'simple' form, but I'd like to be able to store my callback pointer inside a derived type, so that it can be passed around within my Fortran code more easily. So far, nothing I've tried seems to work.
To begin with, here is what I have at the moment, and this does work:
Starting in the C (OK, actually C++) program, the header prototype for the callback is:
typedef void (*fcb)(void *)
and the prototype for the Fortran call is:
extern "C" __declspec(dllexport) int fortran_function(int n,
uchar *image_buffer,
fcb callback,
void *object);
The actual callback function is:
void callback(void* pObject)
{
// Cast the void pointer back to the appropriate class type:
MyClass *pMyObject = static_cast<MyClass *>(pObject);
pMyObject -> updateImageInGUI();
}
and the call to the Fortran code from C++ is:
int error = fortran_function(m_image.size(), m_image.data, callback, this);
where m_image is an array of image data which is a member attribute of the current object. What happens is that the C++ passes the raw image data to the Fortran DLL and asks the Fortran to process it, and since this takes a long time the Fortran periodically updates the image buffer and calls the callback to refresh the GUI. Anyway, moving on to the Fortran side, we define an interface for the C callback:
abstract interface
subroutine c_callback(c_object) bind(c)
use, intrinsic :: iso_c_binding
type(c_ptr), intent(in) :: c_object
end subroutine c_callback
end interface
and define our main Fortran routine thus:
integer(c_int) fortran_function(n, image, callback, c_object) &
bind(c, name='fortran_function')
integer(c_int), value :: n
integer(4), intent(inout), dimension(n) :: image
procedure(c_callback) :: callback
type(c_ptr), intent(in) :: c_object
Somewhere in the main routine we call our subroutine, foo:
call foo(data, callback, c_object)
...where foo is defined as:
subroutine foo(data, callback, c_object)
type(my_type), intent(inout) :: data
procedure(c_callback) :: callback
type(c_ptr), intent(in) :: c_object
...
call callback(c_object)
...
end function foo
As I said, all of this works well and has done so for a long time.
Now for the things I've tried but which don't work:
The naive approach, just copying the arguments into the fields of a structure
I'd expect this to work, since all all I'm doing is to copy the original elements into a structure with no modification. Nothing changes on the C side, nor in the definition of the main Fortran function nor the abstract interface to c_callback. All I do is to create a new Fortran derived type:
type :: callback_data
procedure(c_callback), pointer, nopass :: callback => null()
type(c_ptr) :: c_object
end type callback_data
and then in my main function I populate this with the values received from the C application:
data%callback_data%callback => callback
data%callback_data%c_object = c_object
call foo(data)
The subroutine foo has been slightly modified so that it now looks for the callback and C object within the structure:
subroutine foo(data)
type(my_augmented_type), intent(inout) :: data
...
call data%callback_data%callback(data%callback_data%c_object)
...
end function foo
This fails at the call with an "access violation reading location 0xffffffffffffffff".
The sophisticated approach using more of the iso_c_binding features
Again nothing changes on the C side but I modify the Fortran side of the main function to receive the callback as a c_funptr:
integer(c_int) fortran_function(n, image, callback, c_object) &
bind(c, name='fortran_function')
integer(c_int), value :: n
integer(4), intent(inout), dimension(n) :: image
type(c_funptr), intent(in) :: callback
type(c_ptr), intent(in) :: c_object
I define the abstract interface to subroutine c_callback just as before, though I've experimented both with leaving the bind(c) part of it in, and omitting it. The code within the main function that calls the subroutine foo is now:
call c_f_procpointer(callback, data%callback_data%callback)
data%callback_data%c_object = c_object
call foo(data)
...with the subroutine foo itself still defined as in the previous example.
Unfortunately this fails in exactly the same way as the previous example.
I assume that there is a correct syntax to achieve what I'm trying to achieve here, and I'd be very grateful for any advice.
A dummy argument in a Fortran procedure with the BIND(C) attribute that doesn't have the VALUE argument is equivalent on the C side to a pointer parameter (this is broadly consistent with the usual Fortran convention of things being passed by reference). So if on the Fortran side you have INTEGER(C_INT) :: a (no value attribute), that's equivalent on the C side to int *a.
Perhaps that's obvious, but it has a surprising consequence - if you have TYPE(C_PTR) :: p, that's equivalent to void **p - a C_PTR is a pointer, so a C_PTR passed without value is a pointer to a pointer. Given this, your interface for the callback is out (you need to add VALUE).
The interoperable analogue in a type sense to a C pointer to a function (which is what a function name sans parentheses is in C) in Fortran is a TYPE(C_FUNPTR). The same considerations with respect to the absence of the VALUE attribute and C_PTR apply - an argument declared TYPE(C_FUNPTR) :: f is a pointer to a pointer to a function. Given this and your C side call of the Fortran, the argument corresponding to the function pointer should have the VALUE attribute.
The fact that a Fortran procedure pointer happens to work is just a (not terribly surprising) coincidence of the underlying implementation of C function pointers and Fortran procedure pointers, and the way that Fortran procedure pointers are passed.
All up, your Fortran procedure probably needs to have an interface that looks like:
integer(c_int) fortran_function(n, image, callback, c_object) &
bind(c, name='fortran_function')
integer(c_int), value :: n
integer(c_signed_char), intent(inout), dimension(n) :: image
type(c_funptr), intent(in), value :: callback
type(c_ptr), intent(in), value :: c_object
(your declaration of the image array in your original code seems astray - perhaps the above is appropriate, perhaps not)
and your declaration of the interface of the C callback needs to have an interface of:
abstract interface
subroutine c_callback(c_object) bind(c)
use, intrinsic :: iso_c_binding
implicit none
type(c_ptr), intent(in), value :: c_object
end subroutine c_callback
end interface
(As discussed on the Intel fora over the last few months (where have you been?), current ifort may have a problem with it's handling of C_PTR and VALUE.)

Expose saved/static target variable to scope outside

Is the following code where a local, saved variable is exposed to an outside scope valid Fortran(>=2003) code?
I intentionally did not specify a year for the standard. If the answers differ for different standards, assuming that pointers are supported, I would be also happy to hear the answer.
program test_save
implicit none
integer, pointer :: ptr
ptr => get_number(5)
write(*, *) ptr
contains
function get_number(n) result(res)
integer, intent(in) :: n
integer, pointer :: res
integer, target, save :: internal_n
internal_n = n
res => internal_n
end function
end program
The point to consider is whether the target of res remains defined when the function exits (F2018 19.6.6p1(16)). Because the target has the SAVE attribute, it does remain defined (F2018 19.6.6p1(3)), and therefore the pointer remains defined.

Fortran Derived Type Operators

I am a bit confused as I am running my code to do scalar-vector multiplication using u = v * scalar and v = scalar * u
I thought the following code would give me ambiguous declaration for
the generic '*'. How are the functions vsm_real32, vsm_real64, and
vsm_real128 not conflicting with function svm?
Procedure :: vsm_real32, vsm_real64, &
vsm_real128
Procedure, Pass (tb) :: svm
Generic :: Operator (*) => vsm_real32, &
vsm_real64, vsm_real128, &
svm
Contains
Function vsm_real32 (tb, sc_real32) Result (ta)
Type (Vector) :: ta
Class (Vector), Intent (In) :: tb
Real (Real32), Intent (In) :: sc_real32
Call vsmd (ta, tb, sc_real32, "*")
End Function vsm_real32
Function vsm_real64 (tb, sc_real64) Result (ta)
Type (Vector) :: ta
Class (Vector), Intent (In) :: tb
Real (Real64), Intent (In) :: sc_real64
Call vsmd (ta, tb, sc_real64, "*")
End Function vsm_real64
Function vsm_real128 (tb, sc_real128) Result (ta)
Type (Vector) :: ta
Class (Vector), Intent (In) :: tb
Real (Real128), Intent (In) :: sc_real128
Call vsmd (ta, tb, sc_real128, "*")
End Function vsm_real128
Function svm (sc, tb) Result (ta)
Type (Vector) :: ta
Class (*), Intent (In) :: sc
Class (Vector), Intent (In) :: tb
Call vsmd (ta, tb, sc, "*")
End Function svm
The generic binding is for an operator. The requirement for procedures to be distinguishable is based on the position of the dummy arguments only.
(For the expression a * b, the first dummy argument always corresponds to a, the second to b. Passed arguments don't influence disambiguation in this case.)
The vsm_* functions all have a required second dummy argument that varies in real kind from function to function. That second argument is therefore distinguishable, therefore the vsm_* functions are all distinguishable.
The second argument of svm function is of type Vector. This is a different type to the type of the second argument of the vsm_* functions (REAL), therefore the second argument is distinguishable, therefore the svm function is distinguishable from all of the vsm_* functions.
Refer F2008 C1212.