Skip to main content
GitHub

Limit the scope of variables and procedures

Variables and procedures shall be declared in the minimum scope from which all references to the identifier are possible.

Using a broader scope than necessary increases maintenance cost and the likelihood of unintended name resolution or modification. Restricting scope reduces namespace pollution and limits access to identifiers from unrelated program units.

In modern Fortran, adhering to this rule includes:

  1. Avoid using global or module-level variables when local variables or argument passing are sufficient.
  2. Declaring variables within the smallest enclosing block or procedure in which they are used.
  3. Restricting the visibility of module procedures using the private attribute.

Noncompliant Code Example

In this noncompliant example, the function helper_calc is intended for internal use by the public_routine . However, in Fortran, module procedures have public visibility by default. As a result, helper_calc is accessible to any program unit that uses math_mod , unnecessarily exposing an internal implementation detail.

Non-compliant code
module math_mod
  implicit none

contains 
  ! Noncompliant: Default public visibility
  function helper_calc(x) result(y)
    real, intent(in) :: x
    real :: y
    y = x * 2.0
  end function helper_calc

  subroutine public_routine(val)
    real, intent(inout) :: val
    val = helper_calc(val)
  end subroutine public_routine

end module math_mod

Compliant Solution

In this compliant solution, the private statement is applied at the module level to change the default visibility of all entities to private. The intended public interface is then explicitly declared using the public_routine using the public attribute. This confines helper_calc to the module scope and prevents unintended external use.

Compliant code
module math_mod
  implicit none
  private ! Sets default visibility to private
  public :: public_routine

contains 
  ! Compliant: Only visible within math_mod
  function helper_calc(x) result(y)
    real, intent(in) :: x
    real             :: y
    y = x * 2.0
  end function helper_calc

  subroutine public_routine(val)
    real, intent(inout) :: val
    val = helper_calc(val)
  end subroutine public_routine

end module math_mod

Noncompliant Code Example

In this noncompliant code example, the variable current_count is declared at the module level. The subroutine update_counter depends on this global variable, giving it unnecessarily wide scope. Any program unit that uses counter_mod can access or modify current_count, increasing the risk or unintended interactions.

Non-compliant code
module counter_mod
  implicit none
  integer            :: current_count = 0 ! Noncompliant Scope is too wide
  integer, parameter :: MAX_COUNT = 100

contains

  subroutine update_counter()
    if (current_count < MAX_COUNT) then
      current_count = current_count + 1
    end if
  end subroutine update_counter

end module counter_mod

Compliant Solution

In this compliant solution, current_count is declared local to the subroutine with the SAVE attribute. This limits visibility to update_counter while maintaining its value between calls. The global namespace is protected, and other program units cannot modify current_count directly.

Compliant code
module counter_mod
  implicit none
  integer, parameter :: MAX_COUNT = 100

contains

  subroutine update_counter()
    ! Compliant: Scope is limited to this subroutine
    integer, save :: current_count = 0

    if (current_count < MAX_COUNT) then
        current_count = current_count + 1
    end if
  end subroutine update_counter

end module counter_mod

Risk Assessment

Failure to minimize scope limits the compiler's ability to optimize and increases the likelihood of name collisions and unintended side effects. It degrades the locality of reference and makes the code difficult to review and maintain.

RecommendationSeverityLikelihoodDetectableRepairablePriorityLevel
SAD01-FLowUnlikelyYesYesP3L3

Attachments: