Fortran: 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 moreFortran: Service Composition, part 2: Decoration
In the previous post we saw how to use an abstraction to compose an aggregation of services of that same abstraction. There we simply delegated a call, adding no specific behavior. But we might as well add some new behavior before or after delegating the call.
As an example, let’s try to implement a new feature in the logging module: we want to add a timestamp in front of each message, so the output becomes something like this:
By Matthias Noback
read moreFortran: Service Composition, part 1: Aggregation
With our new service abstraction logger_t
we are able to easily implement more features for our logger. We can do this without affecting current user code, because their code relies only on the abstraction, never on concrete implementations.
A terminal output logger
One thing we can do is define a second logger type, one that prints each message to the terminal output (stdout
). Being a logger, it should also extend the abstract logger_t
type, and provide an implementation for log()
:
By Matthias Noback
read more