Correct use of modules, subroutines and functions

2019-01-03 15:01发布

I've recently learnt about tinterface blocks when adding a function to my Fortran program. Everything works nice and neatly, but now I want to add a second function into the interface block.

Here is my interface block:

interface
    function correctNeighLabel (A,i,j,k)
    integer :: correctNeighLabel
    integer, intent(in) :: i,j,k
    integer,dimension(:,:,:),intent(inout) :: A
    end function

    function correctNeighArray (B,d,e,f)
        character :: correctNeighArray
    integer, intent(in) :: d,e,f
    character, dimension(:,:,:),intent(inout) :: B
    end function
end interface

It appears to me, this may not be the best option.

I've looked into subroutines, but I'm not very confident that it's the right solution. What I'm doing is relatively simple, and I need to pass arguments to the subroutine, but all the subroutines I've seen are a) complicated (i.e. too complicated for a function), and b) don't take arguments, they behave as though they manipulate variables without them being passed to them.

I've not really looked into modules properly, but from what I've seen it's not the right thing to use.

Which should I use when, and how do I go about it best?

3条回答
Emotional °昔
2楼-- · 2019-01-03 15:03

Modules are always the right thing to use ;-)

If you have a very simple F90 program you can include functions and subroutines in the 'contains' block:

 program simple
   implicit none
   integer :: x, y
   x = ...
   y = myfunc(x)
 contains
   function myfunc(x) result(y)
     implicit none
     integer, intent(in)  :: x
     integer              :: y
     ...
   end function myfunc
 end program

Then the interface of the functions/subroutines will be known in the program and don't need to be defined in an interface block.

For more complex programs you should keep all functions/subroutines in modules and load them when required. So you don't need to define interfaces, either:

 module mymod
   implicit none
   private
   public :: myfunc
 contains
   function myfunc(x) result(y)
     implicit none
     integer, intent(in)  :: x
     integer              :: y
     ...
   end function myfunc
 end module mymod

 program advanced
   use mymod, only: myfunc
   implicit none
   integer :: x, y
   x = ...
   y = myfunc(x)
 end program advanced

The module and the program can (actually should) be in separate files, but the module has to be compiled before the actual program.

查看更多
Explosion°爆炸
3楼-- · 2019-01-03 15:04

alexurba's and MSB's answers are correct and useful as usual; let me just flesh out a little more detail on one point - if modules are the way to go (and they are), what are interfaces for at all?

For functions and subroutines in modules, anything that uses that module can automatically see those interfaces; the interfaces are generated when the module is compiled (that information, amongst other things, goes into the .mod file that's generated when you compile a module). So you don't need to write it yourself. Similarly, when you use a CONTAINed subprogram (which, agreeing with MSB, I find more confusing then helpful - they're much better thought of as closures or nested subroutines than external subroutines), the main program can already 'see' the interface explicitly and it doesn't need you to write it out for it.

Interface blocks are for when you can't do this - when the compiler isn't able to generate the explicit interface for you, or when you want something different than what is given. One example is when using C-Fortran interoperability in Fortran 2003. In that case, the Fortran code is linking against some C library (say) and has no way of generating a correct fortran interface to the C routine for you -- you have to do it yourself, by writing your own interface block.

Another example is when you do already know the interfaces to subroutines, but when you want to create a new interface to "hide" the subroutines behind - for instance, when you have one routine that operates on (say) integers, and one on reals, and you want to be able to call the same routine name on either and let the compiler sort it out based on the arguments. Such constructs are called generic routines and have been around since Fortran 90. In that case, you create an interface explicitly to this new generic routine, and list the interfaces to the "real" routines within that interface block.

查看更多
Lonely孤独者°
4楼-- · 2019-01-03 15:13

Seconding and extending what has already been said. It is better to put your procedures (subroutines and functions) into modules and "use" them because them you get automatic consistency checking of the interfaces with little effort. The other ways have drawbacks. If you define the interface with an interface block, then you have three things to maintain instead of two: the interface, the procedure itself and the call. If you make a change, then all three have to be modified to be consistent. If you use a module, only two have to be changed. A reason to use an interface block is if you don't have access to the source code (e.g., pre-compiled library) or the source code is in another language (e.g., you are using C code via the ISO C Binding).

The drawback to the "contains" approach is that contained procedures inherit all of the local variables of the parent program ... which is not very modular and can be very confusing if you forget this "feature".

查看更多
登录 后发表回答