Объем, ассоциация и сокрытие информации в Fortran 90

1

Этот вопрос связан с вызовом и вызываемыми подпрограммами в Fortran 90. Я совершенно запутался в правилах ассоциации host/use/arguments; У меня возникают проблемы с пониманием логики области действия, вытекающей из этих правил. Пожалуй, самый простой способ раскрыть мою проблему — объяснить, чего я хочу добиться и почему.

Я хотел бы удовлетворить два требования к дизайну:

(i) Вызывающая подпрограмма разрешает вызываемой подпрограмме доступ только к своим объектам, которые передаются в качестве аргументов, и никаким другим. (ii) Вызванная подпрограмма не позволяет вызывающей подпрограмме получить доступ ни к одному из объектов, которые она определяет локально.

Если поможет картинка, могу предоставить. Я хотел бы думать о вызывающей и вызываемой подпрограммах как о двух комнатах, соединенных каналом, который они используют для передачи или возврата аргументов. Я хотел бы, чтобы эта ассоциация аргументов была единственным средством, с помощью которого две подпрограммы могли бы иметь какое-либо влияние друг на друга. Я считаю, что код, отвечающий этим требованиям, будет более устойчивым к побочным эффектам. Если я ошибаюсь в этой идее, я был бы признателен, если бы мне объяснили, почему. Если есть веская причина, по которой эти требования нежелательны, я также был бы рад узнать об этом.

2

Конечно, fortran 90 предлагает возможность использования модулей и опцию «только». Например, можно сделать следующее:

module my_mod_a
contains
subroutine my_sub_a
    use my_mod_b, only: my_sub_b
    …
    call my_sub_b(arg_list_b)
    …
end subroutine my_sub_a
end module my_mod_a
!………
module my_mod_b
contains
subroutine my_sub_b(arg_list_b’)
    do stuff with arg_list_b’
end my_sub_b
…
end module my_mod_b
!………

Разумеется, my_sub_a будет разрешен доступ не более чем к тем объектам my_mod_b, для которых my_sub_b является единицей области видимости. Но сможет ли он получить доступ к объектам my_sub_b, отличным от списка аргументов, который он передает? В частности, сможет ли my_sub_a получить доступ к сущностям, локальным для my_sub_b? И наоборот, позволяет ли ассоциация использования my_sub_b получать доступ к объектам my_sub_a, отличным от тех, которые передаются в качестве фактических аргументов?

3

Является ли следующая конструкция «буферного модуля» достаточной для выполнения требований № 1?

module my_mod_a
contains
subroutine my_sub_a
    use my_mod_b_shell, only: my_sub_b_shell
    …
    call my_sub_b_shell(arg_list_b)
    …
end subroutine my_sub_a
end module my_mod_a
!………
module my_mod_b_shell 
contains
subroutine my_sub_b_shell(arg_list_b’)
!passes arguments, does not do anything else
    use my_mod_b, only: my_sub_b
    call my_sub_b(arg_list_b’)
end my_sub_b_shell
end module my_mod_b_shell
!………
module my_mod_b
contains
subroutine my_sub_b(arg_list_b’)
    do stuff with arg_list_b’
end my_sub_b
…
end module my_mod_b
!………

4

Есть ли более простая конструкция для достижения целей № 1?

5

Следуя предложениям, предложенным Россом и Владимиром Ф.,

одна возможность может быть:

(i’) иметь однозначное соответствие между модулями и подпрограммами,

(ii’) объявить локальные переменные в модуле вместо подпрограммы; затем можно пометить локальные переменные как «частные».

Просто чтобы убедиться, что я правильно понял, вот тривиальная программа, которая иллюстрирует (i’) и (ii’):

program main

use sub_a_module
implicit none

double precision :: x

x=0.0d+0
write(*,*) 'x ante:',x
call sub_a(x)
write(*,*) 'x post:',x

end program main
!-------------------------------------------------
module sub_a_module

double precision, private :: u0
double precision, private :: v0
contains
!.-.-.-.-.-.-.-.-
subroutine sub_a(x)

   use sub_b_module
   implicit none

   double precision :: x

   u0=1.0d+0
   v0=2.0d+0
   call sub_b(v0)
   x=x+u0+v0

end subroutine sub_a
!.-.-.-.-.-.-.-.-
end module sub_a_module
!-------------------------------------------------
module sub_b_module

double precision, private :: w0
contains
!.-.-.-.-.-.-.-.-
subroutine sub_b(v)

   implicit none
   double precision :: v

   w0=1.0d-1
   v=v+w0

end subroutine sub_b
!.-.-.-.-.-.-.-.-
end module sub_b_module

В этом примере единственным объектом sub_a, к которому sub_b может получить доступ, является v0 (ассоциация аргументов); u0 останется скрытым для sub_b. И наоборот, тег «private» гарантирует, что переменная w0 останется вне области видимости sub_a, даже если sub_a ИСПОЛЬЗУЕТ модуль sub_b_module. Это правильно?

@Ross: Спасибо, что указали на предыдущий пост, в котором ассоциация наследуется. Однако у меня сложилось впечатление, что это решает только половину моей проблемы; конструкция, обсуждаемая в этом посте, иллюстрирует, как можно запретить вызывающей программной единице доступ к объектам вызываемой программной единицы, которые должны оставаться скрытыми (опции «использовать только» и/или «частные»), но я не могу с уверенностью утверждать, что сущности вызывающей программной единицы, не связанные с аргументами, останутся недоступными для вызываемой программной единицы.


person I.A.S.    schedule 01.10.2017    source источник
comment
Как насчет использования двух отдельных модулей с большинством переменных, установленных как private?   -  person Ross    schedule 02.10.2017
comment
Вы видели это: title="область переменных в случае модулей, используемых модулями в фортране"> stackoverflow.com/questions/42474530/?   -  person Ross    schedule 02.10.2017
comment
@Ross Он не говорит о модулях, он говорит о подпрограммах.   -  person M. Chinoune    schedule 02.10.2017
comment
Я говорил конкретно об ответе Джабирали на этот вопрос. Кроме того, если вас беспокоят ассоциации в современном фортране, конечно, вы должны поговорить о модулях.   -  person Ross    schedule 02.10.2017
comment
Я не совсем понял, о чем вы говорите. но в подпрограммах Фортрана доступ к локальным переменным других подпрограмм невозможен только с помощью аргументов. Пожалуйста, покажите нам пример обратного.   -  person M. Chinoune    schedule 02.10.2017


Ответы (2)


Вы всегда можете создать небольшой модуль, который содержит только подпрограмму и ничего больше, и использовать его из более крупного модуля, который их собирает и который фактически используется для вызова подпрограммы.

Fortran 2015 обеспечивает больший контроль над ассоциацией хостов с помощью IMPORT. Я не уверен, влияет ли это также на процедуры модуля, но может. Но вы просите древний Fortran 90, так что, возможно, вам это неинтересно (компиляторы его все равно еще не реализуют), но я оставлю это здесь на будущее:

Если один оператор импорта в единице области видимости является оператором import,only, все они должны быть такими, и только перечисленные сущности становятся доступными для ассоциации хоста. Если оператор import,none появляется в единице области видимости, никакие объекты не доступны для ассоциации хоста, и это должен быть единственный оператор import в единице области видимости. ... (От: Reid (2017) Новые возможности Fortran 2015)


Да, ваш пример более-менее правильный, хотя возможных вариаций много. Вы всегда можете добавить пункт only, чтобы указать, почему вы используете модуль и какие символы импортируются.

Важно: я предлагаю вам помещать implicit none не внутрь содержащихся процедур, а один раз в модуль. Вы определенно хотите, чтобы переменные модуля были покрыты implicit none! И используйте некоторый отступ, чтобы структура действительно была видна при взгляде на блок кода.

Если вы используете только один исходный файл, вам обязательно нужно поместить туда модули и программу в другом порядке:

module sub_b_module
  implicit none
  double precision, private :: w0

contains

  subroutine sub_b(v)
    double precision :: v

    w0=1.0d-1
    v=v+w0
  end subroutine sub_b
end module sub_b_module

module sub_a_module
  implicit none

  double precision, private :: u0
  double precision, private :: v0

contains

  subroutine sub_a(x)
    use sub_b_module, only: sub_b    
    double precision :: x

    u0=1.0d+0
    v0=2.0d+0        
    call sub_b(v0)       
    x=x+u0+v0
  end subroutine sub_a
end module sub_a_module

program main
  use sub_a_module, only: sub_a
  implicit none

  double precision :: x

  x=0.0d+0
  write(*,*) 'x ante:',x
  call sub_a(x)
  write(*,*) 'x post:',x
end program main

Если вас очень беспокоит доступ к данным, вы можете создать модули mod_sub_a, mod_sub_b, mod_sub_c, каждый из которых содержит только одну общедоступную подпрограмму. Затем модуль subroutines, который их использует, и позволяет всему остальному коду использовать только модуль subroutines для доступа к ним.


Чтобы было ясно - из ответа IanH я вижу, что здесь могло быть некоторое недоразумение - я, конечно, НЕ рекомендую взаимное соответствие модулей и подпрограмм. Я считаю это довольно экстремальным, чтобы убедиться в вашей основной мысли:

Вызывающая подпрограмма позволяет только вызываемой подпрограмме обращаться к своим объектам, которые передаются в качестве аргументов, и никаким другим.

Итак, я показал вам, как убедиться, что ваша подпрограмма не имеет доступа ни к чему извне, поместив ее в модуль, у которого больше нет доступа к чему-либо. Я также показал вам будущий способ с import, который можно использовать для отключения доступа к другим объектам, определенным в хост-модуле.

Я просто проигнорировал ваш второй пункт

Вызываемая подпрограмма не позволяет вызывающей подпрограмме получить доступ ни к одному из объектов, которые она определяет локально.

потому что это выполняется автоматически, если только вызывающая подпрограмма не является внутренней и не содержится в вызывающей подпрограмме.

person Vladimir F    schedule 02.10.2017

Локальные переменные подпрограммы доступны только из области действия этой подпрограммы (и ее внутренних процедур) — поэтому они называются «локальными переменными». Вы можете достичь своих целей дизайна в части 1 вашего вопроса без особых усилий.

Переменные, которые не являются локальными переменными (например, переменные модуля, переменные в общем блоке), могут быть доступны или совместно использовать информацию в разных областях — обычно по этой причине в языке существуют переменные других типов. Если вы не хотите такого обмена информацией, не используйте другие виды переменных!

Предложения в части 5 отредактированного вопроса идут не так...

person IanH    schedule 02.10.2017
comment
Моя точка зрения заключалась в том, чтобы избежать доступа к переменным модуля, которые определены в том же модуле и которые должны использоваться другими процедурами модуля, и как избежать доступа к ним. - person Vladimir F; 03.10.2017