ISO/IEC JTC1/SC22/WG5 N1683 To: WG5 From: Aleksandar Donev Date: 14 July 2007 Subject: Macros should be a TR to F2008 This paper expresses my personal view that the macro feature, as it appears in the F2008 draft, is not sufficiently developed to be included in the standard. I propose that they be made a TR to be published shortly after the standard. This will allow for additional development time, and since they are almost entirely disjoint from the rest of the standard (and in fact macros can be implemented by an external pre-processor) this removal is almost trivial. I will give several reasons why the macro feature is inadequate as it is, and explain each of them in turn: 1) Macro functions are lacking 2) The design was not subject to sufficient debate and input 3) The original goal of "generic programming" is not truly met 1. Macro functions are lacking ---------------- The current macro design only covers statement-level macros, that is, macros that expand to a sequence of statements. In particular, there are no macros that can expand to a token or a token sequence. This design decision was made hastily and without much input from users and the committee, partly because of the rush to finish a preliminary design and partially because the claim was made that to satisfy the "generic programming" requirement statement-level macros were sufficient. The lack of time should not be a constraint for us because this feature can neatly fit in a TR, giving time to develop it further. And the so-called "generic programming" features are severely lacking, and in fact, all we have is a Fortran-aware macro feature. Macros can be used to support some forms of generic programming (albeit not the best way to do so), but at the very least we ought to design the feature so that it is at least as good as something various external macro preprocessors provide. The existing macros are what I would call macro subroutines. The EXPAND statement is like a CALL statement. It is natural to also ask for macro functions, that is, macros that simply expand to a token or a sequence of tokens inside statements. I cannot think of any macro preprocessor in use that does not support macro expansion inside statements, for example, to expand TypeSpec(kind), DIMENSION(10) :: x into INTEGER(KIND=kind), DIMENSION(10) :: x or TYPE(LongInteger(PRECISION=kind)), DIMENSION(10) :: x depending on a macro function definition of TypeSpec. As another example, constructing a constant of kind precision, where precision is, for example, a macro DO variable, requires: MACRO INTEGER :: prec=precision ! Force evaluation to an integer constant x=1.0_&&prec ! Concatenate If we had macro functions, one can write (this is fake syntax of course) this function once in a module: MACRO FUNCTION Evaluate(integer) RESULT(constant) MACRO INTEGER :: constant constant=integer END MACRO and then write: x=1.0_ && Evaluate(precision) whenever forced evaluation is needed. I consider the decision to only provide statement-level macros a fundamental flaw that makes the macro feature soo incomplete that is simply unusable. I would not stop using an external preprocessor to switch to built-in macros, and I wouldn't expect anyone to. I am not saying that there won't be some technical issues to be worked out in order to support macro functions. But, we should not rush a useless "feature" for lack of time. 2. The design was not subject to sufficient debate and input ---------------- There are many small or medium features missing from our macro facility that users will expect. Examples include macro token quoting mechanisms (supression of macro evaluation), variable-argument macro lists, commas and semicolons in macro actual arguments. Most of these are missing because of lack of time to allow suggestions for improvements from committee members and the community. Whenever I proposed something, for example, mechanisms for allowing commas and semincolons in actual arguments, the answer was that the feature was useful but it is too late (i.e., it was "feature creep"). Considering how late in the process even the basic design of macros was rolled out before we closed gaps for "feature creep", it was simply impossible, even for those that read the draft and cared to comment, to affect the design in any meaningful way. This is not the way a committee should work. The point is to work as a group and thus achieve a more complete product than one person would design based on their own (undoubtly incomplete) experience. I will note that in contrast, co-arrays were around for a long long time, and they still changed in important ways based on input from others. For example, memory consistency model, teams, intrinsic coroutines, additional synchronization primitives, the termination model, and many other important features changed or were added. Similarly for BITS, although I was less involved in that so I am not that familiar with the process. 3. The original goal of "generic programming" is not truly met ---------------- The original justification for adding macros to the language was not to add macros but to support (some limited form of) generic programming. I believe that this goal has barely been achieved. What we have is a lexical token manipulation facility. The "intelligence" of the macros goes only so much as to recognize Fortran syntax (lexical tokens, continuation of lines, comments, etc.), and more importantly, proper scoping. The latter is very important, but does not contribute to generic programming per se. We were still adding features only two J3 meetings ago to support even the most basic generic programming example: Writing a routine that operates on different precisions of reals or different integer kinds. We provide an example for this in the draft, and looking at this (and the other examples) reveals how ugly and cumbersome using macros to do this is. Why can't macros know the set of intrinsic kinds of integers or the supported set of REAL kinds? Can't we have features that actually directly support generic programming instead of using token manipulation to get there? It is one thing to foresake error checking (this is the most difficult aspect of generic programming), but to foresake ease of programming is not acceptable. We are left with too little.