Title: The ADDRESS attribute
Submitted by: J3 (Aleksandar Donev, January 2004)
Status: For Consideration
References: J3/03-279r1
Basic Functionality:
I propose that modifications be made to the Fortran standard to allow passing buffers
to C IO/communication routines without explicitly using C_LOC. For this purpose, a new
attribute, spelled ADDRESS in this proposal, is provided. It would only be compatible
with a dummy argument of type TYPE(C_PTR). The C address of the actual argument is
passed by value by the caller.
The actual argument must be a valid argument for the C_LOC intrinsic, in particular,
have the TARGET attribute.
Here is an example:
INTERFACE
SUBROUTINE MPI_Send(buffer, count), BIND(C,"MPI_Send")
TYPE(C_PTR), ADDRESS :: buffer ! New attribute
INTEGER(C_INT), VALUE :: count
END SUBROUTINE
END INTERFACE
! Make this legal:
REAL(C_FLOAT), DIMENSION(...), TARGET :: buffer
CALL MPI_SEND(buffer,10) ! No need for C_LOC
The above problem is similar to the one with "pass-by-value".
Implementations used to deal with C interop with the %VAL intrinsic, so that one had to
wrap a %VAL around any argument in a call that required pass-by-value. The present
system in which the VALUE attribute is present in the interface and there is no
difference at the call site is much better for the user and for code clarity. I am
essentially proposing that a similar solution be implemented to the common problem of
passing the address to an IO-type routine.
Rationale:
Many C libraries dealing with IO/communication, and in particular MPI, have "typeless"
dummy arguments (typically for buffers).
These are typically a void pointer in the C interface. Consider the following
(simplified) C prototype:
void MPI_Send(void * buffer, int count);
and its Fortran equivalent:
INTERFACE
SUBROUTINE MPI_Send(buffer, count), BIND(C,"MPI_Send")
TYPE(C_PTR), VALUE :: buffer
INTEGER(C_INT), VALUE :: count
END SUBROUTINE
END INTERFACE
The actual argument in C can be a pointer (C array) of any type, and an implicit
conversion into a void pointer happens:
float * buffer;
buffer = malloc(...);
MPI_Send(buffer,10); // Works in C
Fortran has a very different system in which the types of the dummy and actual must
match and no implicit conversion happens at the call point. Therefore, one cannot call
the MPI_Send procedure with anything but a C pointer as an actual argument:
REAL(C_FLOAT), DIMENSION(:), TARGET :: buffer
CALL MPI_SEND(buffer,10) ! NOT OK in Fortran
but the following is OK:
CALL MPI_SEND(C_LOC(buffer),10)
The rationale for the proposed solution is two fold:
1) It allows for easier interfacing to numerous existing libraries, including the
existing Fortran interface to MPI (which is flawed as described above), from the user
perspective.
2) It will allow one to reuse current codes, which use vendor extensions or simply
non-conforming tricks to call MPI_SEND with different types. This is friendly to
existing practices.
Estimated Impact:
This will have no cost for the implementations since many implementations already have
a switch that basically lets one have type mismatches, and since the above change is
really just a syntactic wrapper for something everyone already knows how to do: Just
pass the memory address.
Incorporating this into the standard is not entirely trivial. The proposed change will
require that special provisions be made in argument association in the case when the
dummy is a C pointer with the ADDRESS. Essentially what we would say is that it is as
if the user had put a C_LOC in the call:
! This:
CALL MPI_SEND(buffer,10)
! should be the same as:
CALL MPI_SEND(C_LOC(buffer),10)
Whether we relax the requirement that the actual be a TARGET (since the actual of C_LOC
needs to) is a different matter. I would suggest that TARGET be required. If TARGET were
optional, there are issues to consider here such as contiguity requirements and the
provision for copy in/copy out (think Interp 125), as well as the risk of allowing
pointers to be taken by the C procedure and abused, even in a legal program. I would
like to say that, in some cases, one wants to make sure no copy in/copy out happens
(such as asynchronous communication calls), and in Fortran using the TARGET attribute
is the *only* way to ensure this (Interp 125).
Detailed Specification:
A dummy argument interoperable with a C pointer may have the ADDRESS attribute. The
VALUE attribute is implied by the ADDRESS attribute, but may be duplicated.
If the dummy argument has the ADDRESS attribute, the actual argument must be a valid
actual argument for C_LOC. The value of the result of C_LOC applied to the actual
argument, i.e., the C address of the actual argument, is associated with the dummy.
History:
Comment:
Malcolm Cohen, Nihon NAG, Tokyo:
This reminds me of a Kurt Hirchert suggestion to allow a TARGET actual
to be passed to a POINTER dummy. This is analagous to passing an
expression value to a dummy variable (no-one thinks we should have been
limited to passing variables instead of values).
This suggestion is very similar - one has (effectively) a POINTER VALUE
dummy argument and wants a TARGET to turn into a POINTER. I think that
Kurt's suggestion is much more attractive than just doing it for C
interop.
Furthermore, the idea of doing automatic coercions on argument
association is completely foreign to Fortran. C has automatic
conversions, which is the only reason you don't see typecasts everywhere
on function references. I'm not sure that this is where I'd start
adding them either. The argument that it uglifies the call to say
CALL csub(C_LOC(my_var))
I find a bit unconvincing. It is even more ugly to say
x = cpown(REAL(y1-y2,C_DOUBLE),INT(n+1,C_LONG))
but noone is suggesting we do anything about that!
We already have a fully polymorphic pointer in Fortran, it's called
CLASS(*). If we want to have one that is completely unsafe to use,
perhaps TYPE(*) is a better way of spelling it than TYPE(C_PTR). Then a
TYPE(*) dummy would interoperate with a (void *) C pointer.
Finally, if we're going to have automatic conversions for TYPE(C_PTR)
let's just have them. Drop the unnecessary syntax. If TYPE(C_PTR) is
going to be magic, let's just make it magic and not have a special
attribute "MAGIC" which is ***ONLY*** applicable to TYPE(C_PTR).
SUMMARY: (1) I'd rather see an unsafe TYPE(*) added, with whatever
operations necessary [perhaps just conversion to another
pointer type, perhaps some I/O support].
(2) Should we not consider the Hirchert idea as well?
(3) If we're really wedded to the idea of only doing this for
C interop, drop the syntax. Just do it.