ISO/IEC JTC1/SC22/WG5 N1766 Result letter ballot 5 on technical content of N1761 John Reid, 8 January 2009 This is result of the letter ballot (N1763) that WG5 agreed to hold in view of there being insufficient time in Tokyo to discuss the technical content of the TR on "Further Interoperability of Fortran with C". WG5 members were asked to answer the following question "Do you approve of the technical content of N1761?" in one or more of these ways (it is acceptable to choose both 2 and 3). 1) Yes. 2) Yes, with comments. 3) Yes, except with OPTIONAL dummy arguments in interoperable interfaces removed, with comments. 4) No, with comments (comments required). 5) Abstain. The votes were as follows: 1) Yes. Rasmussen 2) Yes, with comments. Donev Snyder 3) Yes, except with OPTIONAL dummy arguments in interoperable interfaces removed, with comments. 4) No, with comments (comments required). Bader Chivers Ingrassia Maclaren Muxworthy Reid Sleightholme Xia 5) Abstain. Morgan Takata The following comments were submitted: ...................................................................................... Donev I believe this TR requires additional work before there is reasonable agreement on technical content, yet alone before it is ready for publication. It's publication should not be rushed before it is ready because it is a very important TR. Technical comments: 1) I sent an example to the J3 list for which I did not receive an answer. It is not clear whether it was intended to allow an associated or allocated CLASS(*) (unlimited polymorphic) actual argument to correspond to an assumed-type dummy argument? I believe this should be allowed but I cannot figure out what if anything the TR . 2) If a BIND(C) routine has a dummy that is assumed-type, the present draft allows one to pass an actual that is of non interoperable type. This is likely intended but if so that should be stated so there is no confusion. 3) The present mechanism for making a typeless (assumed-type) dummy usable is to use C_F_POINTER to point a Fortran pointer to it, see the last example in the TR. This is syntactically ugly, and does not transfer strides for non-contiguous objects. It is much better to allow a direct pointer assignment statement for this purpose, similarly to how we allow one to point a typed Fortran pointer to a CLASS(*) target. Here is a nice example that cannot be done with the present TR: subroutine process(block) type(*), dimension(:,:), target :: block(*) ! May be non-contiguous integer, pointer :: usable(:,:) usable=>block ! Copies bounds, strides, etc. usable=0 ! Instead of the disallowed block=0 end subroutine 4) The statement "In other respects, the rules for assumed-rank dummy arguments are similar to those for assumed-shape arrays" should be clarified by making a list of all of these rules. 5) I agree with Bader that a SELECT RANK should be considered to allow assumed-rank arrays to be used directly in Fortran. 6) The routine CFI_update_fdesc is constrained to use malloc. I agree with another comment that it is better to add a destruction routine and not force the use of malloc upon the implementation. 7) I agree with Bader that the routine CFI_is_contiguous is better done as a function that also returns false for not allocated. 8) The function CFI_bounds_to_cdesc assumes a contiguous object, and this should be stated. The function CFI_cdesc_to_bounds can only work for contiguous objects as well, and this should be stated. I believe it is a useless function. 9) Concerning the sentence "A C descriptor associated with such memory shall not be supplied as an argument to CFI_deallocate and a corresponding dummy argument in a called Fortran procedure shall not be specified in a context that would cause the dummy argument to be deallocated." Is there a context other than an explicit DEALLOCATE in which pointers are deallocated? Also, concerning the subsequent: "If a Fortran descriptor is created by a C function, the memory for the descriptor may be released by a reference to the free library function in a C function when the descriptor is no longer needed." Delete this sentence or replace "may be released" with "It is the programmer's responsibility to release". The memory may be released by reference to the free library function in a C function. 10) Reinhold Bader has suggested DIMENSION(**) to specify dummies that can be matched by actuals of any rank, including scalars. 11) The present draft uses CFI_MAX_RANK to make the bounds/stride information in the C descriptors a fixed-size array. An alternative design, which has some important advantages, is to use a flexible array member for this purpose. If we make such a change, we should add some macros to more easily manipulate the flexible array members. ...................................................................................... Snyder A C descriptor has a flag that indicates whether a pointer is or is not associated. It's not always possible to tell. It is always possible to tell whether a pointer is or is not disassociated. Whenever "type" is used it should be clear whether it's C type or Fortran type. It's not explicit, and therefore not clear, in a few places. The "sm" component of a CFI_dim_t struct is specified to be measured in bytes. This should be in processor-dependent units. In the fourth paragraph of the "Assumed-shape, ..." section, shouldn't it be possible to deallocate a pointer object? ...................................................................................... Bader References: ftp://ftp.nag.co.uk/sc22wg5/N1751-N1800/N1761.txt http://j3-fortran.org/doc/meeting/186/08-295.txt My response is "NO, with comments". The comments are provided below in the form of a list of issues, examples and suggestions. The minimum required to make me say YES is: * Issues 1, 2, 4 and 6 must be fixed. Issue 4 may be regarded as a showstopper by those from the MPI Forum who require existing infrastructure to be preserved, while providing improved Fortran interfaces. Issue 1 - missing examples for usage of descriptors: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ I've tried to supply one which could be added to the draft; it is also used here to illustrate further TR issues. Example 1: C calling a Fortran implementation module mod_foo use, intrinsic :: iso_c_binding type, bind(c) :: foo integer(c_int) :: i real(c_float) :: r(3) character(c_int) :: c end type contains subroutine construct_foo(this, n, i, r, c) bind(c) ! bind(c) extended for TR29113 type(foo), allocatable, intent(out) :: this(:) integer(c_int), intent(in) :: n, i(n) real(c_float), intent(in) :: r(3, n) character(c_char), intent(in) :: c(n) : ! code for constructing this end subroutine end module C client code: #include /* interface */ void construct_foo(void *, int, int *, float *, char *); /* matching type definition */ typedef struct { int i; float r[3]; char c; } Foo; int main() { CFI_desc_t *my_desc; type Foo *array_elem; int :: istatus; int i[4] = { 1, 2, 3, 4 }; float r[4][3] = { { 1.0, 1.1, 1.2 }, { 2.0, 2.1, 2.2 }, { 3.0, 3.1, 3.2 }, { 4.0, 4.1, 4.2 } }; char c[4] = { 'a', 'b', 'c', 'd' }; my_desc = (CFI_desc_t *) malloc(sizeof(CFI_desc_t)); my_desc->base_addr = NULL; my_desc->elem_len = sizeof(Foo); /* may need Fortran call to C_SIZEOF if unknown */ my_desc->rank = 1; my_desc->type = CFI_type_struct; my_desc->attribute = CFI_attribute_allocatable; my_desc->state = 0; my_desc->fdesc = NULL; istatus = CFI_update_fdesc(my_desc); /* make attributes known to processor */ construct_foo(my_desc->fdesc, 4, i, r, c); istatus = CFI_update_cdesc(my_desc); /* update attributes for C program */ /* align 3rd element to C scalar of matching type. (for contiguous Fortran arrays one could also align a C array) */ array_elem = (Foo *)(base_addr + 2 * sizeof(Foo)); printf("Character component of 3rd element: %s\n",array_elem->c); istatus = CFI_deallocate(my_desc); free(my_desc); } Issue 2 - polymorphism of assumed-type entity: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Since no changes to the definition of C_LOC() have been introduced, and this function is used to cast an object of TYPE(*) to a usable type, the text beginning in line 92 of N1761 should be replaced by "In the association of actual and dummy arguments, an assumed-type dummy argument is type and kind compatible with a non-polymorphic actual data argument of any type." Issue 3 - interface of CFI_is_contiguous: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ I'd suggest _Bool CFI_is_contiguous(const CFI_cdesc_t *) and have it return false if a dynamic object is not allocated. The typical usage would then be more concise: if (mydesc->state && CFI_is_contiguous(mydesc)) ... Issue 4 - rank matching for generics: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The example provided in line 552-575 of N1761 is not conforming, since on of the uses of the interface contravenes p290, para 13 of the F2008 draft standard 08-007r2, which disallows matching of actual arguments of arbitrary ranks to the assumed size dummy of rank one for a generic interface. Either one must give up using a generic interface, in which case two separate calls must be provided for the scalar and array arguments, or a feature must be added to the language which allows to pass an argument of arbitrary rank by address / sequence association. Suggestion 2 below tries to provide an extension which solves this problem. Issue 5 - RANK intrinsic: ~~~~~~~~~~~~~~~~~~~~~~~~~~ Is this really needed considering we already have SIZE(SHAPE(X))? Issue 6 - referencing or defining assumed rank entities: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ We need some rules to deal with this. Unless some checks normally performed at compile time are deferred to run time, introducing a SELECT RANK block construct might be appropriate. real, dimension(::) :: a real, pointer :: p(:) select rank (a) case(0) a = 1. case(1) a(:) = [ ... ] default ... ! no references or definitions of a allowed here end select It might also be feasible to allow a pointer of rank 1 to point at such an object: p => a if (i < size(a)) then ... = p(i) end if This would however imply a re-interpretation of scalar actuals as rank 1 entities of size 1. Issue 7 - non-interoperable types: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ While I've heard it said that coverage of non-interoperable types was not the purpose of this TR, I wonder whether this is not implicitly already contained, at least for non-interoperable entities with following properties: * non-polymorphic, non-sequence * allocatable or pointer type components * ultimate type components of interoperable intrinsic type Assumed-shape/assumed-rank/allocatable/pointer, scalars and arrays of this type would be acceptable as dummy arguments, based on the existing capabilities of the descriptors. [since BIND is not a characteristic of a dummy argument, normal scalars may be a problem. Since allocatable scalars or pointer scalars can be used, it is not really a big problem.] So, if the type definition from example 1 above were replaced by type :: foo integer(c_int) :: i real(c_float), allocatable :: r(:) character(c_int) :: c end type the unpacking process in C would need to use a type definition typedef struct { int i; void *fdesc; char c; } Foo; Once an object of this type is mapped to an array element, either CFI_update_cdesc() can be used to access the type component, or (if Suggestion 1 below is adopted), the CFI_create_desc() constructor with a non-NULL last argument. [If type fields and dummy arguments use different descriptors, it may be necessary to introduce another component of CFI_desc_t, say tf_desc.] Issue 8 - C variable argument lists: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ with the changes introduced in 08-295 it should now also be possible to provide support for vararg interfaces by matching to specifics of a Fortran generic interface. The only obstruction to this would be dealing with c_char arguments; this however might also be solved by Suggestion 2 below. Suggestion 1 (design change interface creation): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This is an attempt to formulate an alternative to the descriptor usage (and, to a lesser extent, design) described in N1761. The idea is to * improve proper separation of concerns * require the processor to auto-generate code which under the present proposal must be inserted manually, and thereby improve usability. After a first description I'll attempt to illustrate the advantages compared to N1761 via example programs. Since the attributes presently not supported for interoperable procedure arguments (assumed shape, pointer, allocatable, and perhaps also non-interoperable types) are characteristics, the processor is in principle capable of disambiguating interfaces using these features from those previously available for C interoperation. Hence I do not consider it necessary to provide a separate attribute with the BIND statement. (A) C calling a Fortran implementation: The matching C interface is replaced by an auto-generated mapped C interface. For example 1, this would be void construct_foo(CFI_desc_t *, int, int *, float *, char *); It would be the responsibility of the processor to * generate a local name by which the procedure name is known in Fortran * generate a global name based on the default label of the Fortran entity, unless a binding label is specified. (These two items could be handled analogously to the treatment of Fortran external procedures with no binding label (08-295)). * automatically generate a wrapper which performs any updates covered by CFI_update_fdesc in the present design, unwraps the entity CFI_desc_t and hands on the Fortran descriptor field to the Fortran-local procedure call. A direct call from Fortran to the global C name is non-conforming since no type matching CFI_desc_t is available within Fortran; the processor should prevent an interface attempting this from being created. * after return from the Fortran-local procedure performs any updates which are covered by CFI_update_cdesc in the present design. It is further suggested to provide a constructor (and associated destructor) function for the descriptor itself which has as its arguments those entities the programmer is responsible for. The call to the constructor would replace the simple malloc() and the immediately following field settings in the example 1 above. The necessary creation of the fdesc field should also be performed in this constructor unless a non-NULL value is supplied in the last argument, replacing this functionality in CFI_update_fdesc(). If a non-NULL value if provided for fdesc, a consistent C descriptor is created, ignoring the other arguments. Here the interfaces: CFI_desc_t *CFI_create_desc(size_t elem_len, int rank, int type, int attribute, void *fdesc); void CFI_destroy_desc(CFI_desc_t *cdesc, _Bool destroy_fdesc); and two constants for readability: CFI_destroy_fdesc (_Bool with value true) CFI_keep_fdesc (_Bool with value false) In contrast to statically determined Fortran code the constructor sets the attribute, type and rank of an object at run time. Do we oblige the processor to update this information if inconsistent with the defined Fortran interface? All other type fields of a CFI_desc_t object should not be explicitly set by the user, except for other calls to the processor-defined routines. The API calls CFI_update_fdesc() and CFI_update_cdesc() should be removed. The net amount of function call overhead would stay the same, but usability is improved at least for the real inter-language case. The C main() of example 1 above would thus read int main() { CFI_desc_t *my_desc; type Foo *array_elem; int :: istatus; int i[4] = { 1, 2, 3, 4 }; float r[4][3] = { { 1.0, 1.1, 1.2 }, { 2.0, 2.1, 2.2 }, { 3.0, 3.1, 3.2 }, { 4.0, 4.1, 4.2 } }; char c[4] = { 'a', 'b', 'c', 'd' }; my_desc = CFI_create_desc(sizeof(Foo), 1, CFI_type_struct, CFI_attribute_allocatable, NULL); construct_foo(my_desc, 4, i, r, c); /* align 3rd element to C scalar of matching type. (for contiguous Fortran arrays one could also align a C array) */ array_elem = (Foo *)(base_addr + 2 * sizeof(Foo)); printf("Character component of 3rd element: %s\n",array_elem->c); istatus = CFI_deallocate(my_desc); CFI_destroy_desc(my_desc, CFI_destroy_fdesc); } (B) Fortran calling a C implementation: The wrapper generated from the interface * packs up the Fortran descriptor into a C descriptor upon call to the local Fortran name, which is automatically generated for this purpose * executes the C routine and once the C routine has finished * updates the Fortran descriptor, and then deallocates the C descriptor without destroying the Fortran descriptor. Run time checks may be required to assure no incompatibilities with statically defined properties have been introduced. It is not intended that the Fortran local name be dereferenced from C. A C program calling the C interface (untypical) would need to perform the construction and allocation, deallocation and destruction of descriptors manually before and after the call, respectively. As an example, suppose we were to implement a modern MPI Interface. Example 2: module mpi use, intrinsic :: iso_c_binding implicit none private ! various C interoperable opaque type definitions not shown here public :: mpi_send interface subroutine mpi_send(buf, datatype, elem_size, dest, tag, comm, ierror) bind(c) type(*), dimension(..), contiguous, intent(in) :: buf type(mpi_datatype), intent(in) :: datatype integer(c_size_t), optional, intent(in) :: elem_size integer(c_int), intent(in) :: dest, ierror integer(c_size_t), optional, intent(in) :: tag type(mpi_comm), intent(in) :: comm end subroutine end interface end module The C implementation could look something like this: #include void mpi_send(CFI_desc_t *buf, MPI_Ftype *datatype, size_t *elem_size, int *dest, size_t *tag, MPI_Comm *comm, int *ierror) { int local_size = 0; /* bytes */ int i; void *local_buf; if (buf->state == 0) { *ierror = ...; /* may want to send length 0 buffer? */ return; } if (MPI_Ftype->MPI_Datatype == MPI_INT) local_size = 4; if (MPI_Ftype->MPI_Datatype == MPI_FLOAT) local_size = ...; /* etc. */ if (elem_size != NULL && MPI_Ftype->MPI_Datatype == MPI_DERIVED) { local_size = *elem_size; } if (local_size == 0) { *ierror = ...; return; } for (i=0; irank) { local_count *= buf->dim[i]->extent; } *ierror = MPI_Send(buf->base_addr, local_count, MPI_BYTE, *dest, *tag, *comm); } this single call would cover * scalars and contiguous arrays of arbitrary rank (is "contiguous" unambiguous here?) * all intrinsic types defined in MPI * all C interoperable types (with a static type structure, and in a slightly less safe manner than when using the MPI datatype constructors) A C implementation might for example be of advantage over a Fortran one if it is easier to obtain certain type-internal information from C (e.g., the MPI_Ftype->MPI_Datatype dereferences). Note that this also illustrates that OPTIONAL arguments can also be handled by the wrapping process (i.e., non-present arguments will be set NULL on the call to the C entity). In particular, the problem with having the combination of OPTIONAL and VALUE (not used in this example) attributes vanishes (for non-c_ptr types a convention may be needed). Suggestion 2 (add assumed-rank-and-size): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ in analogy to assumed rank (DIMENSION(::)), which one might also call assumed-rank-and-shape, a dummy variable can be declared with type(foo), DIMENSION(**) :: dummy A corresponding actual argument which is either a scalar or an arbitrary rank array of type foo would match this dummy argument and it would be allowed to have exactly one corresponding dummy with this attribute in a specific procedure of a generic interface when all other dummies have the same characteristics. The only allowed method of dereferencing or defining such an object from within Fortran would be via one dimensional indexing: dummy(i) = ... A BIND(C) interface may specify dummy arguments that are assumed-rank-and-size. If the dummy argument is assumed-rank-and-size, the actual argument is passed as its C address. Otherwise, the restrictions on this kind of argument will be essentially the same as those for assumed-size entities. Example 2a: extending the generic interface of example 1 for old-style calls. module mpi use, intrinsic :: iso_c_binding implicit none private ! various C interoperable opaque type definitions not shown here public :: mpi_send interface subroutine mpif_send(buf, count, datatype, dest, tag, comm, ierror) & bind(c, name='MPIF_Send') type(*), dimension(**), intent(in) :: buf integer(c_int) :: dataype, dest, tag, comm, ierror end subroutine subroutine mpi_send(buf, datatype, elem_size, dest, tag, comm, ierror) bind(c) type(*), dimension(..), contiguous, intent(in) :: buf type(mpi_datatype), intent(in) :: datatype integer(c_size_t), optional, intent(in) :: elem_size integer(c_int), intent(in) :: dest, ierror integer(c_size_t), optional, intent(in) :: tag type(mpi_comm), intent(in) :: comm end subroutine end interface end module Note however that the ierror argument is still Fortran-style, so a direct mapping to the C MPI_Send routine is not possible. With the old-style call, derived datatypes must be dealt with via the MPI datatype construction routines; apart from that the same functionality is available as for the new call, only in a slightly less type-safe manner. Additional notes: * processing of C interoperable string entities would be straightforward using this, making the special rule introduced for this case in F2003 superfluous. * the added bonus is that this also supports using character arguments in generic interfaces. ...................................................................................... Chivers My major concern is timing. The emphasis should be on getting the final cd out as soon as possible. ...................................................................................... Ingrassia 0) The file ISO_Fortran_binding.h does not appear to be included with N1761. I assume this is an oversight? 1) The general approach of standardizing a data structure (incompletely) seems awkward compared to the approach of standardizing the particular sorts of APIs that programmers will want (e.g. what is the rank? what is the base address? please change the base address, etc.) Standardizing a structure might make it difficult to change the structure from one compiler release to the next, as the structure is "frozen" in the ABI. 2) There is no "version" query for the structure or the ABI. If a vendor makes changes from one release to the next, does the user have any portable way of detecting differences? 3) If C descriptors and Fortran descriptors are in true correspondence, then it is hard to understand the reason for an asymmetry where the C descriptor has an fdesc field but the Fortran descriptor need not have a cdesc field or equivalent. 4) An assumed-rank variable cannot appear in many contexts. It therefore seems like too radical a syntax change for the benefit obtained. Some such syntax as %REF for passing addresses of objects might be simpler and has some actual deployment history. 5) A TR advancing interoperability of Fortran with C should make some mention of variadic functions. 6) The user model seems needlessly complex, or I am not understanding all of it. It is called a "two descriptor model" but given that the API supplies ways of synthesizing multiple descriptors to refer to the same "physical" data object, it seems that there are really any number of descriptors. The API allows "efficient" access to objects defined by descriptors, but does not permit a full calculus of descriptors (do two descriptors describe the same object?). Since some user-initiated actions like deallocation require an implementation to be able to distinguish descriptors, it's not clear that the API is complete enough. ...................................................................................... Maclaren 1. Comments on N1761 -------------------- 1) It is unclear what it is proposing for normative text, proposing for informative text, or merely including as discussion. In some cases, it is hard to work out exactly what it is proposing. It should be redrafted to be much closer to the ISO/IEC Directives, Part 2, Rules for the structure and drafting of International Standards (which also applies to Technical Reports). 2) Its overall design is seriously limited, will cause difficulty for some implementations in many ways (which is at the heart of the OPTIONAL controversy), and does not allow for future standard or processor extension. It also does not support the most important required interoperability aspects (e.g. (a) below). For these reasons, I think that it needs a redesign, starting from a much more clearly stated set of objectives. In particular, those objectives should include at least: a) the ability to call the MPI transfer functions with arrays of interoperable derived types as choice arguments; b) to avoid introducing unnecessary restrictions and artificial distinctions between Fortran features. For example, the current proposal allows for the passing of assumed-shape arrays but not assumed-length CHARACTER, and requires entirely separate code to handle explicit-shape and assumed-shape arrays; c) to be at least potentially extensible to interfacing with the C variable argument list mechanism, or the many languages that use a dynamic type system; d) to at least potentially permit the companion processor to be a debugging tool (preferably passing object bounds across the interface for all arguments); e) to at least potentially permit interfacing with languages that do not have compatible calling sequences to Fortran (e.g. they use different linkage registers). Please note that these objectives are NOT impracticable; both of (c) and (d) used to be common, and I have implemented (e) more than once. 3) There are some serious design flaws and definite errors in the details, many of which are to do with its use of C, and I append some of them in text (not importance) order. Because of point (1), these comments are necessarily incomplete, often general rather than specific, and I have probably missed several important technical issues. 4) The simplest and cleanest way of resolving many of the issues is to extend the BIND attribute slightly, to allow the programmer to select between the current interface and a descriptor-based one, along the lines of: proc-language-binding-spec is BIND(C[,METHOD=binding_method][NAME=scalar-char-initialization-expr]) binding_method is DIRECT or DESCRIPTOR The default is DIRECT, and is what we have at present. I have started drafting a design, and will circulate it separately, but shall not have time for more work on it before late January. 5) The UK's requirement against N1763 for MPI support also needs support for non-blocking and one-sided transfers, it was answered by being referred to this proposed Technical Report, but there is nothing on those in it. I am pretty sure that it is straightforward, though tricky to phrase, and have started drafting some proposals, but I do not have time to work on it now. 2. DESIGN FLAWS AND ERRORS IN N1761 ----------------------------------- Introduction ------------ I assume this section is entirely discussion. Optional arguments ------------------ I have no special comments on this section, except to note that excluding the combination of OPTIONAL and VALUE is technically unnecessary. Assumed-type variables ---------------------- There is no reason to exclude the VALUE attribute, as the C argument is a pointer. Assumed-rank variables ---------------------- There is no reason to exclude the VALUE attribute, as the C argument is a pointer. I do not know what the wording "In other respects, the rules for assumed-rank dummy arguments are similar to those for assumed-shape arrays" means, and whether it proposes any constraints on either the processor or programmer. Object Descriptors ------------------ I assume this section is entirely discussion. Fortran descriptors ------------------- It is unclear why this section is present at all, as it is purely about (fairly obvious) implementation details. I assume that it is entirely discussion. C descriptors ------------- A "pointer of type void" is meaningless - C has no data type "void". The terminology should be fixed, everywhere the wording is used. "The C descriptor is a struct of type CFI_desc_t" is ambiguous. Is the type "struct CFI_desc_t" (as "struct tm" in time.h) or "CFI_desc_t" (as "div_t" in stdlib.h)? The design does not support ALLOCATABLE and POINTER arrays cleanly; in particular, the C descriptor does not contain enough information to update the pointer value correctly. Changing the base address in the descriptor alone will NOT work. The specification of the "attribute" field is broken. Inter alia, it mixes type properties with attributes, does not allow assumed-shape arrays to be allocatable or pointers, and makes no reference to assumed-rank. I am not sure exactly what it is proposing, or why. If it is needed, it should specify the attributes as bits in a mask. The description of the "state" field is baffling. Why should assumed-shape but not assumed-rank be included together with associated pointers and allocable variables? I assume that there is an error, but am not sure what it is. It is completely unnecessary for "dim" to be specified of being a fixed length. C has the concept of a flexible array member as the last element of a structure (C99 6.7.2.1, paragraph 16). That would enable all of the references to CFI_MAX_RANK to be removed. The type "intptr_t" is unsuitable for array indexing, as it was introduced for entirely separate purposes, and could be very inefficient on some systems. For example, on the IBM AS/400 (a 'capability' system), it would need to be 64 bytes. With some reasonable parallel implementations, pointers and hence intptr_t would include the processor/image identifier (e.g. be 16 bytes, of which only 8 was relevant). "ptrdiff_t" is a far better type for the purpose. This issue also arises in the next section. The specification must say which kind of C constants are defined in the file ISO_Fortran_binding.h, as C has several, with different properties. That would need careful design. Most of them should be preprocessor constants suitable for use in #if directives, but perhaps not all. The types need to include a non-interoperable type, for use with assumed-type arguments. The existing standard already allows them to be passed between Fortran and C. Assumed-shape, assumed-rank, allocatable, data pointer arguments ---------------------------------------------------------------- For some reason, this contains most of the description of ISO_Fortran_binding.h; that should be extracted to a separate section. The specification of ISO_Fortran_binding.h is seriously incomplete. For example, it should be specified to be unitary (as the standard C headers are). The level of namespace pollution must also be specified, for future enhancements. That is very important for C. The layout of C structures is very dependent on the compiler options. In the existing Fortran standard, the processor can (in theory, at least) remap structures. Because N1761 proposes structures to use as the actual interface descriptors, that is not feasible. The matter needs consideration. The descriptor functions are impure and return an error code through their function result. Because they are C interfaces, that is plausible, but it is undesirable to use a specification that conflicts with Fortran's conventions. In particular, it would obstruct a vendor or future version of the standard from defining them as interoperable procedures. That option should be left open. It seems that the descriptor functions use the supplied descriptors both as the source of data and where they store the results, but they do not specify which fields must be set on entry and which are set on exit. It is essential to fix that - or, preferably, use a cleaner interface. CFI_update_fdesc is specified to use malloc, but that is an unreasonable restriction on an implementation; the requirement should be removed. CFI_allocate says "The supplied bounds override any current dimension information in the descriptors. The stride values are ignored and assumed to be one. Both the Fortran and C descriptors are updated by this function." That makes no sense, as it would leave the descriptors in an invalid state. The intent of CFI_bounds_to_cdesc is unclear, especially as it does not say that creating an invalid descriptor is forbidden. The description of stride "equal to the difference between the subscript values of consecutive elements of an array along a specified dimension" makes no sense when applied to a dummy argument - it is always one. Fortran has no concept of the strides of the actual arguments being visible to the called procedure. "The base address in the C descriptor for a data pointer may be modified by assignment and that change later affected in the corresponding Fortran descriptor by the CFI_update_fdesc function" means that allocatable and pointer arrays can be changed other than by calls to CFI_allocate and CFI_deallocate (which is stated to be forbidden elsewhere). Something is wrong, but I don't know what. There is a lot of missing wording - such as forbidding the bounds array to have a higher rank than the descriptor. =========================== The examples use "integer(8)" to indicate an 8-byte integer set up by a compiler option "-i8". That is completely processor-dependent, and should not be included in a Technical Report. The examples use MPI names, but are wildly invalid. They should use MPI correctly, or not refer to it. ...................................................................................... Muxworthy Various concerns about the technical details in the TR, including the extent of coverage to conform to N1760 section 2.2 and indeed the basic design (cf Maclaren's vote), have been raised since the ballot was issued. Until these have been resolved by the editorial group my vote is no. On the particular question of allowing optional dummy arguments: YES Other comment: The document is not yet in the format required by ISO/ IEC Directives (Part 2, Clauses 6 & 7). ...................................................................................... Reid My reason for the NO vote is that I would like to see support for MPI non-blocking procedure calls. My major comment concerns timing. In my report to SC22 (N1737), I said 'It is envisaged that the first draft of the TR on Further Interoperability of Fortran with C will be forwarded by March 2009'. I think we need to abandon this aim. It was envisaged that the detailed work on the TR be done in the slack time while the standard was out for vote, not in the busy time after the vote is in and the responses agreed. We need to concentrate on the preparation of the Final CD in the early months of 2009. My minor comments (using line numbers in N1761) follow. 45-47. The concepts of assumed type and assumed rank are useful within Fortran too, as the final example illustrates. 102-103. Change 'If ... assumed-size array, the' to 'The'. [As far as I can see, this restriction is not needed.] 104-107. The sentence should be a separate paragraph and preferably moved to another section since it applies to more than assumed-type variables. 344-346. What does it mean if the specifiers have the same value? 414. Change to 'using the mechanism of the Fortran ALLOCATE statement. On' 451. Change to 'information for one dimension of an array section. It is defined in the file' ^^^^^^^ 466. Change to 'modified by assignment and that change later effected in the' ^ 470. Surely it is necessary to be able to call CFI_update_cdesc for an allocatable object. 470-473. Why would the programmer want to change such a base address? Why not disallow it? 519. What units are used for the size? 520-521. Change to 'generic interface allows the size to be given by alternative kinds of integers'. [I don't know what the "-i8" compiler switch problem is.] 573. Why is y of rank 0? 574. y(:,1) is contiguous so no copy is ever needed. 575. Why is this illegal, rather than rank 0? 628+. More examples needed, showing the use of descriptors. ...................................................................................... Sleightholme I think we need to concentrate on the final CD first. Quoting John Reid : [Repetition of John Reid's comments] ...................................................................................... Xia 1.) OPTIONAL argument The current design does not support OPTIONAL argument with VALUE attribute. This is a fundamental technical flaw in the design. The Fortran 2003 standard allows VALUE to be specified with OPTIONAL argument, while in the TR this combination becomes illegal. This obviously is an adverse change compared to F03. It should also be noted that one solution that supports this particular combination was proposed, but it was rejected due to the implementation convenience of a few vendors. 2.) Fortran descriptors Although Fortran descriptors are used when passing assumed-shape arrays, pointer arrays and allocatable arrays by many vendors, they are however not universally used by all vendors. Based on a survey earlier this year (by Craig Rasmussen at J3 m183), some vendors haven't adopted descriptors for assumed shape arrays, pointer arrays or allocatable arrays. The requirement in the C-interop TR may pose implementation difficulties for those vendors. Furthermore allowing updates on Fortran descriptors from C programs will likely cause safety issues and also be problematic in consistency check by some vendors. This becomes a sure way to introduce bugs difficult to diagnose. 3.) assumed-type and assumed-rank These two features were not in the original scope of TR 29113. They were proposed (08-271r1) to be added to this TR in an attempt to respond to the requirement from MPI community for something similar to IGNORE_TKR directives already implemented by a number of vendors. These features are of more urgent and important nature than the OPTIONAL or the descriptor features in TR 29113. Therefore it is more desirable to devote effort and study to these features in a separate TR. ...................................................................................... Morgan I haven't had time to look at this properly so I abstain. ...................................................................................... Takata I have given up to closely look at the content of N1761. I had no time to do so, sorry. I abstain from the ballot.