ADS01-F. Explicitly declare pure procedures
Procedures that do not produce side effects shall be explicitly declared with the pure prefix. From Fortran 2018 onwards, procedures that are side-effect-free and do not reference external data may additionally be declared simple .
A pure procedure is guaranteed by the compiler to be free from side effects. According to the Fortran standard, a pure procedure must not modify any variable accessed by a host or use association, nor can it perform external input/output operations. Explicitly declaring a procedure as pure:
- Enforces data flow discipline. It requires that all dummy arguments of a function have
intent(in)(orvalue) and that subroutines have explicit intents for all arguments, reducing the risk or unintended data modifications. - Enables parallel safety. Pure procedures are required for use within
do concurrentconstructs andforallstatements because their lack of side effects prevents race conditions in unordered execution segments. - Facilitates scoping analysis. It provides the compiler and the developer with valuable hints regarding data scoping, which is critical for avoiding pitfalls like race conditions in parallel programming.
From Fortran 2018 onwards, the standard introduced simple procedures . A simple procedure is a stricter form of a pure procedure. In addition to having no side effects, a simple procedure must not reference any variable accessed by use or host association. A simple procedure depends solely on its arguments, meaning its return value is determined entirely by its inputs, ensuring referential transparency.
Noncompliant Code Example
In this noncompliant example, the function calculate_circle_area() has no side effects, but because it is not declared pure . Without this attribute, its side-effect-free behavior is not explicitly stated in the interface, and the compiler cannot enforce the semantic constraints associated with pure procedures.
module geometry_mod
implicit none
real, parameter :: PI = 3.14159
contains
! Noncompliant: Effectively pure procedure but not declared as such
function calculate_circle_area(radius) result(area)
real, intent(in) :: radius
real :: area
area = PI * radius**2
end function calculate_circle_area
end module geometry_mod
Compliant Solution
In this compliant solution, the programmer explicitly states that the function has no side effects by adding the pure attribute. The compiler verifies this contract, enforcing restrictions such as requiring intent(in) on the dummy argument radius and preventing modification of module data like PI . This makes the procedure's behavior explicit and verifiable.
module geometry_mod
implicit none
real, parameter :: PI = 3.14159
contains
! Compliant: Procedure declared pure explicitly
pure function calculate_circle_area(radius) result(area)
real, intent(in) :: radius
real :: area
area = PI * radius**2
end function calculate_circle_area
end module geometry_mod
Noncompliant Code Example
In this noncompliant example, the function apply_scaling() reads the module variable scale_factor . Although the code does not modify it, the absence ot the pure attribute means this property is not formally declared or checked. The procedure's side-effect behavior is therefore implicit rather than enforced.
module scaling_mod
implicit none
real :: scale_factor = 2.5
contains
! Noncompliant: Effectively pure procedure as reading global state without modification is allowed
function apply_scaling(val) result(res)
real, intent(in) :: val
real :: res
res = val * scale_factor
end function apply_scaling
end module scaling_mod
Compliant Solution
In this compliant solution, declaring apply_scaling() as pure makes the absence of side effects part of the procedure's interface contract. The compiler enforces that scale_factor is not modified, and that the function adheres to the restrictions required for pure procedures, ensuring consistent and well-defined behavior.
module scaling_mod
implicit none
real :: scale_factor = 2.5
contains
! Compliant: Procedure declared pure explicitly
pure function apply_scaling(val) result(res)
real, intent(in) :: val
real :: res
res = val * scale_factor
end function apply_scaling
end module scaling_mod
Risk Assessment
Failing to declare side-effect-free procedures as pure or simple deprives the compiler and developers of essential guarantees regarding data independence. This omission prevents the compiler from enforcing read-only constraints on global data, increasing the likelihood of unintended state modification and hidden data coupling. Furthermore, without these attributes, the compiler cannot verify thread safety, potentially leading to data races and undefined behavior if the procedure is used in parallel constructs like do concurrent . This obscures the data flow, making the codebase significantly harder to audit for correctness and security vulnerabilities.
| Recommendation | Severity | Likelihood | Detectable | Repairable | Priority | Level |
| ADS01-F | Low | Unlikely | Yes | Yes | P3 | L3 |
Bibliography
| [ Fortran 2023 Interpretation Document ] | Sections: 15.7 and 15.8 |
Attachments:
button_arrow_left.png (image/png)
button_arrow_up.png (image/png)
button_arrow_right.png (image/png)


