Harvey,
I missed the earlier discussion since I was then not subscribing to the list.
Here are some comments I have been stacking up during my own work.
For reasons of inter-procedural analysis that many compilers do within a
source code file it is often nice to group subroutines into files. This
grouping can also reflect some connection between these subroutines. (E.g.
ioroutines.f90, preanal.f90, solving.f90, utils.f90 etc.) As a project
grows - and in particular if you inherit someone else's large F77 project
there may not be one-directional dependencies between these files. I.e. you
are not able to make each of these files into one module that contains the
subroutines. The reason being that would you create module ioroutines and
module module utils it turns out that routines in utils are USEing routines
in module utils and other routines in module utils are USEing routines in
module ioroutines. When the number of routines are in the order of several
hundreds it becomes cumbersome to sort this out. There are three major lines
taken I guess:
1) Make each subroutine its own module in its own source code file. This
disables many optimizations like e.g. inlining for compilers that do
not have good support for cross source-file optimizations. On the other
hand it is fairly straightforward to write a Makefile that has the correct
dependencies for creating both .mod and .o files. Apart from possible
compiler optimizations bing lost the structure of the program is also
lost as logically connected routines are not longer grouped together in
source files.
2) Make each subroutine its own module but keeping them in the same source
code file as earlier. This solution has the same draw-back as the outline
above that you may find yourself in situations where you can't compile
any of files A.f90 and B.f90 before the other as they depend on module
information from the other file. Makefile construction is harder in this
case - in particular writing a Makefile that is portable.
3) Keep the subroutines in the original file and write a separate file
containing a module with the corresponding interfaces for the routines.
This module is then USEd by each unit that needs to call a routine in
the file. The win is that the files containing the interfaces can be
compiled first and the USEd in the compilation of the actual routines.
The loss is that it is even more of a challenge to write a correct Makefile
and keep it up to date with code changes. Also, of course, keeping the
interfaces consistent with the subroutines in question is a pain.
There are tools that tries to aid you in keeping interfaces consistent as well
as keeping Makefile dependencies correct. Being rather dependent on the CPP
pre-processor in most of my major projects it is not so easy to use these tools
though. Most compilers today support natively the use of CPP processed files.
If these compilers included options for writing interfaces and/or dependencies
life would be a lot easier. I am not requesting that they should be able to
write interfaces for the general case - if they wrote the interface for the
CPP-flags submitted to the compiler it would be useful enough. And aiming for
more than that would probably cause the interfaces to become un-useable or at
least un-readable.
In the mean time I think the language would gain if it included the following:
1) If it would be allowed to include the interface declaration for a subroutine
in the subroutine definition itself. And that the language enforces that if
this is done the interface information must be used to verify that the
subroutine definition and the interface are consistent.
2) That the language included a recommendation that compilers supported an option
for treating all subroutine references without an explicit interface as a
compile time error. (Because it is a pain when you find out that there is
a call somewhere that is incorrect, but there was no inclusion of the correct
interface in that unit)
I find tools that automatically write interfaces etc extremely useful today
to create the first version of interface definitions. However, since I tend
to use CPP to separate e.g. serial and parallel versions and/or 2D and 3D
versions of a code, I find myself doing incremental modifications manually
most of the time. Or, I run the code through CPP to generate ONE version of
the code that I then use to create interfaces/dependencies whereafter I sit
down and insert the #ifdef's needed for the other cases by hand.
Those are my on-top-of-the-head opinions on your question.
/Nils
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Nils Jönsson http://www.pdc.kth.se/
Center for Parallel Computers e-mail: [log in to unmask]
Royal Institute of Technology Voice: +46-8-7909115
KTH Fax: +46-8-247784
S-100 44 Stockholm, Sweden Office: OB2, room 1546
-----------------------------------------------------------------------
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|