Моя точка зрения состояла в основном в том, чтобы избежать доступа к переменным модуля, которые определены в том же модуле и которые должны использоваться другими процедурами модуля, и как избежать доступа к ним.

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

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

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

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

(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: Спасибо, что указали на предыдущий пост, где связь унаследована. Однако у меня сложилось впечатление, что это касается только половины моей проблемы; конструкция, обсуждаемая в этом посте, иллюстрирует, как можно запретить программному модулю вызывающей стороны получить доступ к объектам вызываемого программного модуля, которые должны оставаться скрытыми (опции «использовать только» и / или «частные»), но я не могу с уверенностью утверждать, что объекты программной единицы вызывающей стороны, которые не связаны с аргументами, останутся недоступными для вызываемой программной единицы.

 M. Chinoune02 окт. 2017 г., 07:07
@ Росс Он не говорит о модулях, он занимается подпрограммами.
 Ross02 окт. 2017 г., 07:09
Я конкретно говорил об ответе Джабирали на этот вопрос. Кроме того, если вы беспокоитесь об ассоциации в современном Fortran,конечно Вы должны говорить о модулях.
 Ross02 окт. 2017 г., 05:47
Как насчет использования двух отдельных модулей с большинством переменных, установленных какprivate?
 Ross02 окт. 2017 г., 05:48
 M. Chinoune02 окт. 2017 г., 07:11
Я не совсем понял, о чем ты говоришь. но в Fortran подпрограммы не могут получить доступ к локальным переменным других подпрограмм только по аргументам. Пожалуйста, покажите нам пример обратного.

Ответы на вопрос(2)

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

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

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

 Vladimir F02 окт. 2017 г., 23:40
Моя точка зрения состояла в основном в том, чтобы избежать доступа к переменным модуля, которые определены в том же модуле и которые должны использоваться другими процедурами модуля, и как избежать доступа к ним.

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

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 это можно использовать для отключения доступа к другим объектам, определенным в модуле хоста.

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

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

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

Ваш ответ на вопрос