I am aware one can use an interface to create a single name for multiple functions. In fact, I've done so in a small code for something like that:
interface assert_equal
procedure assert_equal_int
procedure assert_equal_real
procedure assert_equal_string
end interface
However, I noticed that most of the time I just need the first two dummy arguments of the function to implement some sort of equality. If I was trying to do this in Haskell, for instance, I would do something like
assertEqual :: (Eq a) => a -> a -> String -> IO ()
Where the first two arguments are the values being checked against each other and the third one is a message.
Or in Rust I would do, for instance
impl {
fn assert_equal<T>(expected: T, actual: T, msg: &str) where T: std::Eq {
...
# enter code here
}
}
Is there something similar or that at least emulates the same behaviour in Fortran? The current issue I am trying to solve is being able to do some sort of assert_equal
in derived types that I will create in my code base, without needing to define a specific subroutine for each derived type when they are going to look so similar
With fypp you can quite easily achieve such a behaviour:
#:def assert_equal(a, b, message="")
if (any([${a}$ /= ${b}$])) then
write(*, *) "assert_equal violated"
write(*, *) ${a}$, '/=', ${b}$
#:if message
write(*, *) ${message}$
#:endif
error stop
end if
#:enddef
program test_assert
implicit none
@:assert_equal(4, 4)
@:assert_equal([3, 4], [3, 4])
@:assert_equal(4., 4.)
@:assert_equal("4", "4")
@:assert_equal("4", "5", "this is my cool message")
end program
Which can be compiled via fypp test_assert.fpp > test_assert.f90 && gfortran test_assert.f90
Note that because we use any([${a}$ /= ${b}$])
instead of ${a}$ /= ${b}$
it works for both scalar and array values, as long as a /=
operation is defined.
Note that for most numerical codes I would actually not use an assert_equal
like this:
|a - b| < epsilon
criterion.sum((A - B)**2) < epsilon
) instead of just ensuring element wise equality.For this reason I would rather recommend to only supply an assert
macro.
Then developers will write something like:
@:assert(near_zero(sum((A - B)**2))))
when comparing two floating point arrays A
and B
.
PS: We use a similar approach in a largeish quantum chemistry program here.