|
|
 |
 |
 |
 |
Fortran Programming Language
|
 |
 |
 |
 |
 |
 |
 |
 |
generic routines, to what end?
I make a good deal of use of "records," defined types consolidating the data spectific to some entity. Typically for record types foo and bar, I will have a foo module and a bar module, defining the respective types and supplying the subroutines necessary to process them. Often, the routines that I write to process different types of records are almost identical across record types; they will often differ only in the definition section, where one will will say "TYPE(foo),INTENT(in) :: rec", and another will say "TYPE(bar),INTENT(in) :: rec", and otherwise the code will be identical. To process records, say, confabulate them, I will often have subroutines foo_confabulate and bar_confabulate defined in the respective modules, and I will define a generic interface with this in the foo module: INTERFACE confabulate MODULE PROCEDURE foo_confabulate END INTERFACE and the analogous in the bar module. That way in code that uses these modules, I can just go "CALL confabulate(foo_rec)" or "CALL confabulate(bar_rec)". But it seems to me that Fortran's generic interface facility is almost a complete waste of time! I still need to maintain multiple sets of almost identical code, and to endure the consequent pain of having to ensure that any modifications I make are identical as well. And why even bother to define the interface, since I always know whether I want to call foo_confabulate or bar_confabultate, and could call each directly? I suppose I can see the advantages of generic routines from the point of view of an eventual consumer of a library that employs them, but I can see no advantages for anyone who is already familiar with the source code. Most particularly I wish it were possible to write exactly one subroutine and somehow specifiy that it might be called with records of type foo or type bar. (Obviously if this accessed record components, the components accessed would have to be defined on each type of record.) Then at compile time, this could be translated into two different incarnations, saving me the trouble of maintaining multiple source codes. I am somewhat new to Fortran 90/95, so perhaps this indeed is possible? Or something, at any rate, that saves having to maintain several essentially identical routines?
On 3 mei, 15:09, Mark Morss <mfmo@aep.com> wrote:
> I make a good deal of use of "records," defined types consolidating > the data spectific to some entity. Typically for record types foo and > bar, I will have a foo module and a bar module, defining the > respective types and supplying the subroutines necessary to process > them. Often, the routines that I write to process different types of > records are almost identical across record types; they will often > differ only in the definition section, where one will will say > "TYPE(foo),INTENT(in) :: rec", and another will say > "TYPE(bar),INTENT(in) :: rec", and otherwise the code will be > identical. > To process records, say, confabulate them, I will often have > subroutines foo_confabulate and bar_confabulate defined in the > respective modules, and I will define a generic interface with this in > the foo module: > INTERFACE confabulate > MODULE PROCEDURE foo_confabulate > END INTERFACE > and the analogous in the bar module. That way in code that uses these > modules, I can just go "CALL confabulate(foo_rec)" or "CALL > confabulate(bar_rec)". > But it seems to me that Fortran's generic interface facility is almost > a complete waste of time! I still need to maintain multiple sets of > almost identical code, and to endure the consequent pain of having to > ensure that any modifications I make are identical as well. And why > even bother to define the interface, since I always know whether I > want to call foo_confabulate or bar_confabultate, and could call each > directly? > I suppose I can see the advantages of generic routines from the point > of view of an eventual consumer of a library that employs them, but I > can see no advantages for anyone who is already familiar with the > source code. > Most particularly I wish it were possible to write exactly one > subroutine and somehow specifiy that it might be called with records > of type foo or type bar. (Obviously if this accessed record > components, the components accessed would have to be defined on each > type of record.) Then at compile time, this could be translated into > two different incarnations, saving me the trouble of maintaining > multiple source codes. > I am somewhat new to Fortran 90/95, so perhaps this indeed is > possible? Or something, at any rate, that saves having to maintain > several essentially identical routines?
You can achieve this (or something very similar) in Fortran 2003. For Fortran 90/95 the solution might be: - Use INCLUDE to copy identical pieces of code into the source at compile-time - Define a single record type holding the identical pieces and use specific record types to hold the general information and specific information (i.e. aggregation) Something like: type general ... all general stuff end type general type recordA int :: A type(general) :: general_stuff end type recordA And subroutines/functions according to a pattern like this: subroutine print_A( rca ) type(recordA) :: rca write(*,*) 'RecordA:' write(*,*) ' A = ',rca%a call print_general( rca%general_stuff ) end subroutine print_A Regards, Arjen
On May 3, 9:09 am, Mark Morss <mfmo@aep.com> wrote: <snip> > But it seems to me that Fortran's generic interface facility is almost > a complete waste of time! I still need to maintain multiple sets of > almost identical code, and to endure the consequent pain of having to > ensure that any modifications I make are identical as well. And why > even bother to define the interface, since I always know whether I > want to call foo_confabulate or bar_confabultate, and could call each > directly?
Fortran, unlike C++, does not have templates. I have not tried it, but I think the Forpedo http://www.macanics.net/forpedo/index.php preprocessor for Fortran 90 code by Drew McCormack is designed to fill this gap in Fortran. "Forpedo is a preprocessor for Fortran 90 code, written in Python. It can handle some typical preprocessing tasks, like including code from one file in another, but it is mostly designed to provide advanced techniques to pre-Fortran 2003 versions of the language. In particular, there is support for C++ like generics (templates), and run-time polymorphism from Object-Oriented Programming (OOP) (click here for more details on OOP in Fortran)."
On May 3, 9:24 am, Arjen Markus <arjen.mar@wldelft.nl> wrote:
> On 3 mei, 15:09, Mark Morss <mfmo @aep.com> wrote: > > I make a good deal of use of "records," defined types consolidating > > the data spectific to some entity. Typically for record types foo and > > bar, I will have a foo module and a bar module, defining the > > respective types and supplying the subroutines necessary to process > > them. Often, the routines that I write to process different types of > > records are almost identical across record types; they will often > > differ only in the definition section, where one will will say > > "TYPE(foo),INTENT(in) :: rec", and another will say > > "TYPE(bar),INTENT(in) :: rec", and otherwise the code will be > > identical. > > To process records, say, confabulate them, I will often have > > subroutines foo_confabulate and bar_confabulate defined in the > > respective modules, and I will define a generic interface with this in > > the foo module: > > INTERFACE confabulate > > MODULE PROCEDURE foo_confabulate > > END INTERFACE > > and the analogous in the bar module. That way in code that uses these > > modules, I can just go "CALL confabulate(foo_rec)" or "CALL > > confabulate(bar_rec)". > > But it seems to me that Fortran's generic interface facility is almost > > a complete waste of time! I still need to maintain multiple sets of > > almost identical code, and to endure the consequent pain of having to > > ensure that any modifications I make are identical as well. And why > > even bother to define the interface, since I always know whether I > > want to call foo_confabulate or bar_confabultate, and could call each > > directly? > > I suppose I can see the advantages of generic routines from the point > > of view of an eventual consumer of a library that employs them, but I > > can see no advantages for anyone who is already familiar with the > > source code. > > Most particularly I wish it were possible to write exactly one > > subroutine and somehow specifiy that it might be called with records > > of type foo or type bar. (Obviously if this accessed record > > components, the components accessed would have to be defined on each > > type of record.) Then at compile time, this could be translated into > > two different incarnations, saving me the trouble of maintaining > > multiple source codes. > > I am somewhat new to Fortran 90/95, so perhaps this indeed is > > possible? Or something, at any rate, that saves having to maintain > > several essentially identical routines? > You can achieve this (or something very similar) in Fortran 2003. > For Fortran 90/95 the solution might be: > - Use INCLUDE to copy identical pieces of code into the source at > compile-time > - Define a single record type holding the identical pieces and use > specific > record types to hold the general information and specific > information > (i.e. aggregation) > Something like: > type general > ... all general stuff > end type general > type recordA > int :: A > type(general) :: general_stuff > end type recordA > And subroutines/functions according to a pattern like this: > subroutine print_A( rca ) > type(recordA) :: rca > write(*,*) 'RecordA:' > write(*,*) ' A = ',rca%a > call print_general( rca%general_stuff ) > end subroutine print_A > Regards, > Arjen
I have the latest IBM compiler for my system, AIX, but apparently it doesn't implement Fortran 2003. Thanks for those other ideas.
On May 3, 10:02 am, Beliavsky <beliav@aol.com> wrote:
> On May 3, 9:09 am, Mark Morss <mfmo @aep.com> wrote: > <snip> > > But it seems to me that Fortran's generic interface facility is almost > > a complete waste of time! I still need to maintain multiple sets of > > almost identical code, and to endure the consequent pain of having to > > ensure that any modifications I make are identical as well. And why > > even bother to define the interface, since I always know whether I > > want to call foo_confabulate or bar_confabultate, and could call each > > directly? > Fortran, unlike C++, does not have templates. > I have not tried it, but I think the Forpedohttp://www.macanics.net/forpedo/index.php > preprocessor for Fortran 90 code by Drew McCormack is designed to fill > this gap in Fortran. > "Forpedo is a preprocessor for Fortran 90 code, written in Python. It > can handle some typical preprocessing tasks, like including code from > one file in another, but it is mostly designed to provide advanced > techniques to pre-Fortran 2003 versions of the language. In > particular, there is support for C++ like generics (templates), and > run-time polymorphism from Object-Oriented Programming (OOP) (click > here for more details on OOP in Fortran)."
Thanks. I have Python on this machine, so that is definitely an option.
On May 3, 3:09 pm, Mark Morss <mfmo@aep.com> wrote:
> I make a good deal of use of "records," defined types consolidating > the data spectific to some entity. Typically for record types foo and > bar, I will have a foo module and a bar module, defining the > respective types and supplying the subroutines necessary to process > them. Often, the routines that I write to process different types of > records are almost identical across record types; they will often > differ only in the definition section, where one will will say > "TYPE(foo),INTENT(in) :: rec", and another will say > "TYPE(bar),INTENT(in) :: rec", and otherwise the code will be > identical. > To process records, say, confabulate them, I will often have > subroutines foo_confabulate and bar_confabulate defined in the > respective modules, and I will define a generic interface with this in > the foo module: > INTERFACE confabulate > MODULE PROCEDURE foo_confabulate > END INTERFACE > and the analogous in the bar module. That way in code that uses these > modules, I can just go "CALL confabulate(foo_rec)" or "CALL > confabulate(bar_rec)". > But it seems to me that Fortran's generic interface facility is almost > a complete waste of time! I still need to maintain multiple sets of > almost identical code, and to endure the consequent pain of having to > ensure that any modifications I make are identical as well. And why > even bother to define the interface, since I always know whether I > want to call foo_confabulate or bar_confabultate, and could call each > directly? > I suppose I can see the advantages of generic routines from the point > of view of an eventual consumer of a library that employs them, but I > can see no advantages for anyone who is already familiar with the > source code. > Most particularly I wish it were possible to write exactly one > subroutine and somehow specifiy that it might be called with records > of type foo or type bar. (Obviously if this accessed record > components, the components accessed would have to be defined on each > type of record.) Then at compile time, this could be translated into > two different incarnations, saving me the trouble of maintaining > multiple source codes. > I am somewhat new to Fortran 90/95, so perhaps this indeed is > possible? Or something, at any rate, that saves having to maintain > several essentially identical routines?
Fortran 95 does not have templating and F2003 takes only a tiny step in that direction with parameterized types. Templating means generating many procedures from single code block - something different from object polymorphism supported in F2003. F95 generic interfaces actually are all the genericity the user of a library needs (corresponds to overloading in C++). Templating can be achieved only externally, via various macro processors. Others have mentioned Forpedo; I have a good experience with combining m4 with Fortran. In Unix-like environments, m4 is almost always present. I have also written a Vim plugin for doing simple Fortran templating directly inside the editor. Personally, I'm not convinced that templating should be a part of the language. IMHO the only (yet big) advantage of C++ templates over using a macro processor is implicit instantiation. There is a number of disadvantages on the other hand. F2008 may contain "smart macros", which would provide a powerful macro processor inside the language; however, it cannot do implicit instantiation.
In article <1178197743.398867.266@p77g2000hsh.googlegroups.com>, Mark Morss <mfmo@aep.com> wrote: > I still need to maintain multiple sets of > almost identical code, and to endure the consequent pain of having to > ensure that any modifications I make are identical as well.
I think it was pointed out a few posts back that the closest to this that you can do in f90 or f95 is with the INCLUDE statement. The shared code is placed in a separate file, and included into the various specific routines. The specific routines must have the appropriate declarations (which themselves may be parameterized with KIND values), but there is then only one file that has the actual code in it. For example, you can imagine code that defines a single parameter to define the real kind, then then uses the INCLUDE statement to bring in the whole subprogram, declarations and everything. This works well in those cases where the code really doesn't change from one routine to the next. However, in many cases the code does need to change, a little or a lot, depending on the KINDS. For example, a single precision routine might use a table of 10 values to do something (a gaussian quadrature, for example), while the double precision version might need a table of 20 values. In these cases you are faced with writing clever obscure code that abstracts these differences enough so that it can be shared, or writing simple obvious code that is almost the same. There are preprocessors that can do this too. I use filepp which is a perl script (see google for the web site). You basically define a loop, and each pass through the loop outputs a new version of the subprogram. The subroutine name must be a macro that is changed each pass through the loop. This is a little more flexible than a simple INCLUDE statement because you can further define conditional code that changes each pass through the loop. But, as I said above, this is sometimes too clever and obscure to be maintained by more than one person or even by a single person over time. $.02 -Ron Shepard
|
 |
 |
 |
 |
|