Scope of variables in case of modules used by modules in Fortran

余生长醉 提交于 2019-12-01 21:06:48

The best thing to do, in my opinion, is to avoid the use of blanket use statements, especially for large and sometimes unwieldy modules. Instead, specify which module entities to inherit via the only keyword, such as:

program main
   use a_mod, only : c, inc_c
   implicit none

   call inc_c
   write(*,*) c
end program main

This works, but it's confusing because a_mod isn't the real owner of c and inc_c. Therefore, you should try to use entities from where they are actually declared, which gives:

program main
   use c_mod, only : c, inc_c
   !   ^ This has changed
   implicit none

   call inc_c
   write(*,*) c
end program main

Now, anybody reading the code has a clear notion of which variables and subroutines are in scope and where they come from.

Finally, this has the added benefit of reducing the risk that you use c without realizing it's actually inhereted from c_mod. This is particularly a problem when not using implicit none!

As Vladimir F suggested in a comment, you can solve this issue using private and public statements in your modules. If you rewrite your modules like this:

module a_mod
  use :: b_mod

  private
  public :: a

  integer :: a
end module

module b_mod
  use :: c_mod

  private
  public :: b

  integer :: b
end module

module c_mod
  private
  public :: c, inc_c

  integer :: c = 10
contains
  subroutine inc_c
    c = c + 10
  end subroutine
end module

In this case, the statement private in the beginning of each module means that quantities declared in the module are not exported by default. You now have to explicitly declare what variables and subroutines to make available when you use the module by adding a public statement. (This could alternatively be done in one line using the syntax integer, public :: c = 10.) This practice prevents c_mod variables from leaking out of b_mod, and so on.

Though not inituitve like IDE, gfortran can print a list of imported symbols by attaching the -fdump-fortran-original (or -fdump-parse-tree) option. To do so, we first generate *.mod file as

gfortran -c {c,b,a}.f90

and compile the desired source as

gfortran -fdump-fortran-original -c test.f90

Then, we get a list of imported symbols like this:

Namespace: A-Z: (UNKNOWN 0)
procedure name = test
  symtree: 'a'           || symbol: 'a'            
    type spec : (INTEGER 4)
    attributes: (VARIABLE IMPLICIT-SAVE USE-ASSOC(a_mod))
  symtree: 'a_mod'       || symbol: 'a_mod'        
    type spec : (UNKNOWN 0)
    attributes: (MODULE  USE-ASSOC(a_mod))
  symtree: 'b'           || symbol: 'b'            
    type spec : (INTEGER 4)
    attributes: (VARIABLE IMPLICIT-SAVE USE-ASSOC(b_mod))
  symtree: 'b_mod'       || symbol: 'b_mod'        
    type spec : (UNKNOWN 0)
    attributes: (MODULE  USE-ASSOC(b_mod))
  symtree: 'c'           || symbol: 'c'            
    type spec : (INTEGER 4)
    attributes: (VARIABLE IMPLICIT-SAVE USE-ASSOC(c_mod))
  symtree: 'c_mod'       || symbol: 'c_mod'        
    type spec : (UNKNOWN 0)
    attributes: (MODULE  USE-ASSOC(c_mod))
  symtree: 'inc_c'       || symbol: 'inc_c'                             <---        
    type spec : (UNKNOWN 0)                                             <---
    attributes: (PROCEDURE MODULE-PROC  USE-ASSOC(c_mod) SUBROUTINE)    <---
  symtree: 'test'        || symbol: 'test'         
    type spec : (UNKNOWN 0)
    attributes: (PROGRAM PUBLIC  SUBROUTINE)

(For example, the lines with arrow indicates that a routine inc_c is available from c_mod.) If we modify test.f90 so as to attach the only keyword,

program test
  use a_mod, only: inc_c
  implicit none

  call inc_c
end program

then the output is also simplified accordingly:

Namespace: A-Z: (UNKNOWN 0)
procedure name = test
  symtree: 'a_mod'       || symbol: 'a_mod'        
    type spec : (UNKNOWN 0)
    attributes: (MODULE  USE-ASSOC(a_mod))
  symtree: 'inc_c'       || symbol: 'inc_c'        
    type spec : (UNKNOWN 0)
    attributes: (PROCEDURE MODULE-PROC  USE-ASSOC(c_mod) SUBROUTINE)
  symtree: 'test'        || symbol: 'test'         
    type spec : (UNKNOWN 0)
    attributes: (PROGRAM PUBLIC  SUBROUTINE)

So, althogh I've never used this option for this purpose, it might be of some use for the OP's purpose (if really necessary).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!