Skip to content

Commit

Permalink
PWR007: Address bug in solution
Browse files Browse the repository at this point in the history
And streamline the check description for better readability.
  • Loading branch information
alvrogd committed Jan 10, 2025
1 parent b1ab16b commit 722b431
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 43 deletions.
114 changes: 74 additions & 40 deletions Checks/PWR007/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,77 +2,111 @@

### Issue

Implicit data typing is enabled by default and should be avoided since it is
error prone and reduces the legibility of the code.
Fortran allows implicit data typing by default, which is error-prone and
reduces the clarity of the code.

### Actions

Add `implicit none` after the `program` or `module` declaration statement.
Add the `implicit none` statement after the `program`, `module`, or procedure
declaration, while also declaring all variables explicitly to ensure the code
compiles correctly.

### Relevance

Since Fortran 77, variables can be implicitly declared by following certain
conventions. When no type is explicitly declared for a variable, the first
letter of its name is used to determine its type. Thus, when the first letter is
I, J, K, L, M, or N, then the data type is `integer`; otherwise, it is `real`.
This implicit behavior is discouraged since it is error prone and reduces the
legibility of the code. It can be disabled by adding an `implicit none`
statement.
Since Fortran 77, variables can be implicitly declared based on their initial
letter:

> [!NOTE]
> Implicit data typing may lead to unexpected runtime errors. For example, it
> may change the results of the program due to implicit data typing determining
> the type of operation used in computations. Note the example code below shows
> issues with integer/real division operations due to implicit data typing.
- Variables starting with I, J, K, L, M, or N are implicitly typed as
`integer`.
- Variables starting with other letters are implicitly typed as `real`.

This implicit behavior can easily lead to errors and makes the code harder to
understand. For example, a variable intended for floating-point calculations
may be treated as an `integer` because of its name, causing incorrect results.

Implicit typing can be disabled by adding the `implicit none` statement to the
affected `program`, `module`, or procedure. This will force the compiler to
alert of any undeclared variables, helping ensure the correct data types are
used.

> [!TIP]
> Starting with Fortran 2018, it is possible to use the extended form
> `implicit none (type, external)` to disable both implicit variables and
> implicit procedures, which are called through implicit interfaces. This
> approach mitigates the risks associated with such procedures, as outlined in
> [PWR068](/Checks/PWR068/).
> Starting with Fortran 2018, the extended form `implicit none (type,
> external)` disables both implicit variables and implicit procedures, which
> are called through implicit interfaces. This mitigates the risks associated
> with such procedures, as outlined in [PWR068](/Checks/PWR068/).
### Code example

In the following example, the data type of all the variables is determined
implicitly:
In the following example, all variables are implicitly typed:

```fortran
! example.f90
program example
num1 = 7
num2 = 2.5
res = num1 / num2 ! res = 3.0
res = num1 / num2
print *, res
end program example
```

By disabling implicit data typing with the `implicit none` statement, the
compiler raises an error if the data types of all the variables is not declared
explicitly as follows:
As `num1` and `num2` start with the letter N, they are implicitly typed as
`integer`, even though `num2` is intended to hold a floating-point value. As a
result, the division is performed using integer arithmetic, yielding an
incorrect result:

```txt
$ gfortran --version
GNU Fortran (Debian 12.2.0-14) 12.2.0
$ gfortran example.f90 -o example
$ ./example
3.00000000
```

By adding the `implicit none` statement, the compiler will require explicit
declarations for all variables. This helps ensure that `num2` is assigned the
intended data type:

```fortran
program example
! solution.f90
program solution
use iso_fortran_env, only: real32
implicit none
integer :: num1 = 7
real :: num2 = 2.5, res
res = num1 / num2 ! res = 2.799...
end program example
integer :: num1
real(kind=real32) :: num2, res
num1 = 7
num2 = 2.5
res = num1 / num2
print *, res
end program solution
```

Note that the example code above probably fixes a precision issue as well. This
is due to implicit data typing of `num2`, which starts with the letter N and
thus it is implicitly assigned the `integer` type. This leads to the division
`num1 / num2` being an integer division operation (the `real` result `res`
equals `3.0`), instead of the probably intended real division operation (the
`real` result `res` equals `2.799….`).
The division operation will now use floating-point arithmetic, producing a
correct result:

```txt
$ gfortran solution.f90 -o solution
$ ./solution
2.79999995
```

> [!WARNING]
> Note that the variable declarations and initializations are placed on
> separate lines to avoid an unintended `save` behavior. Refer to
> [PWR072](/Checks/PWR072/) for more details.
> [!TIP]
> Although not strictly necessary, `num2` is assigned a specific kind following
> the recommendations outlined in [PWR071](/Checks/PWR071/).
### Related resources

* [PWR007 examples](https://github.com/codee-com/open-catalog/tree/main/Checks/PWR007/)
- [PWR007 examples](https://github.com/codee-com/open-catalog/tree/main/Checks/PWR007/)

### References

* [IMPLICIT - FORTRAN 77 Language Reference, ORACLE](https://docs.oracle.com/cd/E19957-01/805-4939/6j4m0vn9v/index.html),
- [IMPLICIT - FORTRAN 77 Language Reference, ORACLE](https://docs.oracle.com/cd/E19957-01/805-4939/6j4m0vn9v/index.html),
2010 [last checked May 2023]

* [IMPLICIT - Intel® Fortran Compiler Developer Guide and Reference](https://www.intel.com/content/www/us/en/docs/fortran-compiler/developer-guide-reference/2023-2/overview.html),
- [IMPLICIT - Intel® Fortran Compiler Developer Guide and Reference](https://www.intel.com/content/www/us/en/docs/fortran-compiler/developer-guide-reference/2023-2/overview.html),
April 2022 [last checked July 2023]
7 changes: 4 additions & 3 deletions Checks/PWR007/example.f90
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
! PWR007: Disable implicit declaration of variables

subroutine example()
program example
! NOT-PWR071: We`re using implicit typing on purpose
num1 = 7
num2 = 2.5 ! num2 is implicitly typed as integer
res = num1 / num2 ! res = 3.0
end subroutine example
res = num1 / num2
print *, res
end program example
13 changes: 13 additions & 0 deletions Checks/PWR007/solution.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
! PWR007: Disable implicit declaration of variables

program solution
use iso_fortran_env, only: real32
implicit none
integer :: num1
real(kind=real32) :: num2, res

num1 = 7
num2 = 2.5
res = num1 / num2
print *, res
end program solution

0 comments on commit 722b431

Please sign in to comment.