Fortran中的主机关联与使用关联 [英] Host Association vs Use Association in Fortran
问题描述
关于何时一个人比另一个人更可贵的一般规则"吗?
Are there any "general rules" as to when one is preferable to the other?
The context of this question is: I asked a different question regarding host association yesterday (link) and in the comments, I was advised to use host association with caution. The reason being that through host association, it is easy to inadvertently modify variables since the subroutines have unrestricted access to all variables that are declared in the module.
为了说明这一点,我将使用以下代码示例:
To illustrate this, I will use the following code example:
module mod
implicit none
real :: x
contains
subroutine sub(y)
use other_mod, only: a
real, intent(out) :: y
y = a + x
a = a + 1.
x = x + 1.
end subroutine sub
end module mod
a
和 x
均在 sub
中进行了修改.但是对于 x
,我需要遍历所有代码才能看到.通过查看 sub
的声明部分,可以很容易地看到 a
在 sub
中使用(并且可能已修改)的情况.
Both a
and x
are modified in sub
. But for x
, I need to go through all the code to see this. That a
is used in sub
(and possibly modified) can be seen easily by looking at the declaration part of sub
.
从这个意义上讲,似乎最好有两种模块:
In this sense, it seems preferable to have two kinds of modules:
- 一个或多个仅包含变量声明的模块(然后在需要时使用它们 )
- 仅包含过程和可能的参数声明但不包含变量声明的模块
这完全摆脱了变量的主机关联.
This gets rid of host association for variables altogether.
但这似乎不可行,原因有很多:
But this doesn't seem practical for a number of reasons:
- 我可能有十二个子例程在一个模块中使用(和修改)相同的变量.每次必须使用这些变量会使代码混乱,尤其是在其中有很多变量(例如几百个)的情况下.
- 将变量的声明从实际使用的位置分离开似乎使代码难以理解:
- 要么,要么创建一个包含所有声明的巨型控制文件.如果代码很大并且使用许多变量,这可能会造成混乱.
- 或者,为每个模块(或一组模块,如果它们依赖相同的内容)创建一个单独的控制文件.这将使代码本身更易于理解,因为 using 可以立即显示变量的来源.但这会使代码的结构复杂化,从而创建一个非常复杂的文件结构(以及相关的依赖关系结构).
- I might have a dozen subroutines using (and modifying) the same variables in one module. Having to use these variables everytime clutters the code, especially if there are a lot of them (say a few hundred).
- Seperating the declaration of a variable from where it is actually used seems to make the code less comprehensible:
- Either, one creates one giant control file containing all the declarations. This could be quite confusing if the code is large and uses many variables.
- Or, one creates a seperate control file for every module (or group of modules, if they depend on the same content). This would make the code itself better comprehensible, since using the variables immediately shows where they are coming from. But it would complicate the structure of the code, creating a vastly more complicated file structure (and accompanying dependency structure).
最后,所有这些可以归结为:什么时候将变量声明放在使用它们的模块中(以便它们被主机关联使用)更合理?将声明外包给单独的模块更明智(以便在需要时通过使用关联使用变量)?
In the end, all of this boils down to: When is it more sensible to put the declaration of variables in the same module in which they are used (so that they are used by host association) and when is it more sensible to outsource the declaration to a seperate module (so that the variables will be used via use association when they are needed)?
是否有任何一般性准则,或者应根据具体情况决定?而且,如果是个案的话,为什么要选择一个理由呢?
Are there any general guidelines or should this be decided on a case by case basis? And if it is case by case, what are the reasons to go for one over the other?
推荐答案
Fortran提供了几种在不同的程序单元"(主程序,外部过程和模块)之间创建,存储,使用和传递数据的方法.> 1 如您所知,每个程序单元都可以包含内部过程-通过主机关联,它们可以访问主机中包含的任何变量或过程.这通常被视为优势.正如@HighPerformanceMark在其评论中已经提到的,何时使用主机关联或使用关联的一般准则是:
Fortran provides several ways to create, store, use, and pass data between different "program units": the main program, external procedures, and modules.1 As you know, each program unit can contain internal procedures - which, through host association, have access to any variable or procedure contained within the host. This is often seen as an advantage. As mentioned already by @HighPerformanceMark in his comment, the general guideline for when to use host-association or use-association is:
当变量仅(或主要)由同一模块中声明的例程使用时,请使用主机关联;当您要定义要在许多模块中使用的变量时,请使用use-association.
use host-association when variables are only (or mainly) used by routines declared in the same module, and use use-association when you want to define variables to be used in many modules
从您的评论看来,您的主程序中的大多数或所有主机变量都可以通过每个内部过程(大约十二个子例程)进行访问.如果真是这样,那么主机关联似乎是一个非常合理的选择,并且实际上不需要显式地将参数传递给每个子例程.另一方面,如果每个子例程实际上仅使用变量的一个子集,则对其进行更明确的显示可能是合理的.
From your comments, it sounds like most or all of the host variables in your main program are accessed by each internal procedure (about a dozen or so subroutines). If that's the case, then host-association seems like a very reasonable option, and there's really no need to pass in arguments to each subroutine explicitly. On the other hand, if each subroutine actually uses only a subset of the variables, then it might be reasonable to get more explicit about it.
像您一样,我通常不愿意在过程中使用未在参数列表中声明的变量.部分原因是因为我喜欢args列表如何自我记录,并且可以帮助我推断代码以及其中的数据处理方式.与其他工作人员协作时,或者如果我花了一些时间离开代码并且我对它的记忆已经淡出,则更是如此.但是,我发现没有什么理由可以完全避免主机关联,只要您知道主机关联的工作原理并制定策略即可.
Like you, I am generally uncomfortable with using variables within a procedure that haven't been declared in an argument list. This is partly because I like how the list of args is self-documenting, and it helps me to reason about the code and how data is manipulated within it. This is even more true when collaborating with other workers, or if I've spent some time away from the code and my memory of it has faded. However, I've discovered there is little reason to avoid host association altogether, as long as you are aware of how it works and have a strategy.
实际上,我倾向于经常使用内部过程和主机关联,尤其是对于短函数/子例程.我发现将宿主轻松地视为对象",将其变量视为属性"以及任何非常类似于完成工作的对象方法"的内部过程会有所帮助.当然,这是在简化事情,但这确实是重点.
In fact, I tend to use internal procedures and host-association quite often, especially for short functions/subroutines. I find it helpful to loosely think of the host as the "object", its variables as "attributes", and any internal procedures very much like the object's "methods" that do the work. Of course, that's simplifying things, but that's really the point.
对于更复杂的程序,我减少了主"程序本身的主机关联数量,然后该主机关联主要是为了以适当的顺序和上下文调用各种子例程.在这种情况下,我们可以利用
use-association
的优势,并选择直接在需要的程序单元内使用
模块实体(例如过程,变量,类型,参数)他们.我们可以进一步将访问限制为仅使用only:
所需的那些模块实体.这有助于提高可读性,清楚地指示数据流,并且我发现以后更新代码更为简单.您知道,继承,封装等等...但是Fortran风格..................................................................................................................................这实际上是相当不错的.For more complex programs I reduce the amount of host-association from the "main" program itself, which then exists primarily to call the various subroutines in the proper order and context. In this case, we can take advantage of
use-association
and choose touse
module entities (such as procedures, variables, types, parameters) directly within the program unit that needs them. We can further restrict access to only those module entities that are needed withonly:
. This aids readability, the data flow is clearly indicated, and I find that updating the code later is more straightforward. You know, inheritance, encapsulation, and whatnot...but Fortran style. Which is actually pretty good.这是一个示例程序结构,适用于我以及我在Fortran中从事的中等规模的项目.我喜欢将广泛使用的(静态)参数保存在一个单独的模块(或按功能分组的一个或多个模块中)中.我将派生类型和类型绑定过程保留在另一个单独的模块中.如果有用,我将某些模块实体设为
private
,这样就无法从其他程序单元访问它们.我想就是这样.Here's an example program structure that works for me and the moderately-sized projects I've worked on in Fortran. I like to keep my widely-used (static) parameters in a separate module (or modules, if grouped according to function). I keep derived types and type-bound procedures in another separate module(s). If it's useful, I make certain module entities
private
, so that they are not accessible from other program units. And I guess that's it.module params implicit none public !! All items public/accessible by default. integer, parameter :: dp = kind(0.d0) integer, parameter :: nrows = 3 real(dp), parameter :: one=1.0_dp, two=2.0_dp ... end module params module types use params, only: dp, nrows implicit none public !! Public by default. private :: dim2 ... integer, parameter :: dim2 = 3 ... type :: A integer :: id real(dp), dimension(nrows,dim2) :: data contains procedure, pass :: init end type A ... contains subroutine init(self, ...) ... end subroutine init ... end module types module utils implicit none private !! Private by default. public :: workSub1, workSub2, subErr ... integer,save :: count=0 !! Accessible only to entities in this module. ... contains subroutine workSub1(...) ... end subroutine workSub1 subroutine workSub2(...) ... end subroutine workSub2 subroutine subErr(...) ... end subroutine subErr end module utils program main !! An example program structure. use params, only: dp implicit none real(dp) :: xvar, yvar, zvar integer :: n, i logical :: rc call execute_work_subroutines() contains !! Internal procs inherit all vars declared or USEd. subroutine execute_work_subroutines() use types, only: A type(A) :: DataSet !! begin call DataSet%init(i) do i = 1,n call workSub1(xvar,yvar,zvar,A,i,rc) if (rc) call subErr(rc) call workSub2(A,rc) if (rc) call subErr(rc) enddo end subroutine execute_work_subroutines end program main
1 也有子模块,但是我不熟悉它们,也不想提供误导性的信息.对于逻辑上分离大型模块,它们确实很有用.
这篇关于Fortran中的主机关联与使用关联的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!