Fortran: Enumeration, part 3
In the previous post we properly encapsulated the integer
level with a log_level_t
derived type, achieving type safety.
Now, let’s consider the following feature request: we want to show the log level in front of the message. We could do it with decoration of course, but in the scope of this article, let’s do it in the log()
subroutine directly. In this case we’re “lucky” that we can access the module-private data component level
, so we can do a select case
on it to determine what string should be printed:
By Matthias Noback
read moreFortran: Enumeration, part 2
In the previous post we introduced a derived type log_level_t
. The type of data passed to the log()
procedure is still an integer
though:
subroutine log(message, level)
character(len=*), intent(in) :: message
integer, intent(in) :: level
! ...
end subroutine log
This doesn’t stop anyone from passing a completely meaningless integer
value as the level
argument to log()
.
Increasing type-safety
We’d like to increase type-safety and the way to do it is by using a more specific type. In our case, it would be great if we could use log_level_t
as the argument type for level
:
By Matthias Noback
read moreFortran: Enumeration, part 1
In the post about decoration we declared log levels as follows:
module logging_base
! ...
integer, parameter, public :: LOG_DEBUG = 0
integer, parameter, public :: LOG_INFO = 1
integer, parameter, public :: LOG_WARN = 2
integer, parameter, public :: LOG_ERROR = 3
integer, parameter, public :: LOG_FATAL = 4
! ...
end module logging_base
This is somewhat useful, but requires a dedicated only
mention when importing each of these constants, which isn’t very nice:
program main
use logging_base, only: log, LOG_DEBUG, LOG_WARN
! ...
call log('A debug message', LOG_DEBUG)
! ...
call log('A warning', LOG_WARN)
end program main
Although we could live with that, the bigger issue remains: this is not a type-safe solution. Any integer
may be passed as an argument for level
, and the compiler wouldn’t warn us. For example:
By Matthias Noback
read moreFortran: Module Design
Fortran projects are famous for their large modules. Actually, we may also find very large files in legacy projects written in other languages, like Java, PHP, etc. These projects sometimes have files with thousands of lines of code. Fortran projects suffer more from large files I’d say, because:
- IDE support is not great. It’s often still hard to navigate to definitions or usages. There isn’t any support for automated refactorings, like extract function, move function, add parameter, etc. You often can’t get a clear overview of the structure/outline of a file.
- There are no strict indentation rules, making it easy to create a complete mess. Not everyone uses code formatting tools. Code formatting tools that exist and are used, aren’t always very good or easily configurable.
- Fortran code can be hard to read, partially because a lack of curly braces. It’s hard to visually recognize blocks of code. Another reason is that commonly there’s no distinction in letter casing between type names, function names, variable names, etc. Other languages may use CamelCase for types, CAPS for constants, pascalCase for methods, snake_case for functions, etc. In Fortran code, it’s all snake_case.
If there’s anything we can do to make Fortran code easier to deal with, it’s to split the code into smaller parts. We need to have many more modules, each with distinct topics and concerns, so we can get a quick overview of the application’s domain and capabilities. Additionally, this will help us find the right place when we want to make changes to the code.
By Matthias Noback
read more