New standards of fortran are more strict about the mismatches between the calls and the procedure definition. However, there are a lot of legacy codes where, for instance, complex array is viewed as a collection of reals. This still can be properly compiled by lowering such errors to warnings. In gfortran
it is achieved with the -fallow-argument-mismatch
. This provides a temporary working solution, but is unsatisfactory in long-run.
program polymorphic_types_wrk
use Maux_wrk
implicit none
integer, parameter :: dp = kind(1.d0), dim = 10
real(dp) :: wd(2 * dim)
complex(dp) :: wz(dim)
call random_number(wd)
call copy_real_complex_nonconformant(dim, wd, wz)
end program polymorphic_types_wrk
module Maux_wrk
contains
subroutine copy_real_complex_nonconformant(dim, wd, wz)
implicit none
integer, parameter :: dp = kind(1.d0)
integer, intent(in) :: dim
real(dp), intent(in) :: wd(*)
complex(dp), intent(out):: wz(*)
call zcopy(dim, wd, 1, wz, 1)
end subroutine copy_real_complex_nonconformant
end module Maux_wrk
In this example, zcopy
is a standard BLAS subroutine. The goal is to copy an array of reals to an array of complexes assuming the data is contiguous. According to the gfortran
documentation a standard-conformant solution is possible:
Using this option is strongly discouraged. It is possible to provide standard-conforming code which allows different types of arguments by using an explicit interface and TYPE(*).
So, I modified the code respectively, but it does not compile (Assumed-type argument wd
requires an explicit interface):
program polymorphic_types
use Maux
implicit none
integer, parameter :: dp = kind(1.d0), dim = 10
real(dp) :: wd(2 * dim)
complex(dp) :: wz(dim)
call random_number(wd)
call copy_real_complex(dim, wd, wz)
end program polymorphic_types
module Maux
contains
subroutine copy_real_complex(dim, wd, wz)
implicit none
integer, parameter :: dp = kind(1.d0)
integer, intent(in) :: dim
type(*), intent(in) :: wd(..)
complex(dp), intent(out):: wz(..)
call zcopy(dim, wd, 1, wz, 1)
end subroutine copy_real_complex
end module Maux
It puzzles me since all module subroutines are already having an explicit interface. What kind of interface is required?
There is no standard conforming way to associate a real actual argument with a complex dummy argument. That was just as true 45 years ago.
What has changed in 45 years has been the tools available to developers to provide alternatives to non-conforming argument mismatches: first generics and then polymorphism and C interoperability. Compilers have also reduced their tolerance for deliberate violations and improved their diagnostics for unintentional violations.
Assumed type (type(*)
) dummy arguments are a Fortran 2018 form of polymorphism, particularly suited to C interoperability. This is not a form of polymorphism which allows a real actual argument to be associated with a complex dummy argument.
First, to answer about the error about a missing explicit interface. The subroutine copy_real_complex
in the module Maux
does indeed have an explicit interface available in the main program where it is referenced (through use association).
However, the subroutine zcopy
referenced in the subroutine copy_real_complex
does not have an explicit interface available in the subroutine. The compiler is complaining about this missing explicit interface.1
You need to pass a declared complex wd
to zcopy
. An assumed type variable is not a declared complex variable, even if it's a dynamic complex variable (and certainly not if its dynamic type is something completely different).
If you want to make all your argument associations compliant, then you'll need to convert (in some way) your wd
to a complex entity. This answer is about the need of/complaints about an explicit interface, but you can find other questions, such as this one about how you can do that conversion. There are ways without lying to your compiler about type matching, but you may decide that -fallow-argument-mismatch
is just about acceptable.
The compiler documentation's comments about the use of type(*)
allowing the writing of standard-conforming code is about how, in this case, zcopy
could be written. It's not about how something which calls zcopy
should be written.
For practical examples, see how MPI's Fortran 2008 bindings take advantage of type(*)
and dimension(..)
. These allow a single specific procedure such as MPI_SEND
to take buffers of any type and rank and don't require the same characteristics in each reference.
Finally, for the case of the question, the type mismatch makes assumptions about how default real and complex are stored. The Fortran standard gives some assurance about this storage, but much less assurance about the storage of non-default real and non-default complex.
If you want to avoid -fallow-argument-mismatch
you will need to write conforming code and that conforming code will need the actual arguments to BLAS's zcopy
to be complex and not real. Consistently using complex entities can be one way, noting
call random_number(wz%Re)
call random_number(wz%Im)
won't require any hacks. CBLAS also provides an interface to a language which is much less fussy about type matching.
1 Although when we look at the definition of BLAS zcopy
there's nothing there that requires an explicit interface when referenced, the compiler doesn't know what zcopy
looks like. Recall that "explicit" and "implicit" interfaces aren't properties of the procedure itself, but are about what's known in the place referencing the procedure.
Instead, the compiler knows that a conforming call means that zcopy
has a polymorphic dummy argument: the variable wd
which is an actual argument is polymorphic, and polymorphic in a way that it may be associated only with a default argument which is polymorphic. A polymorphic dummy argument requires an explicit interface.
The reference in the subroutine copy_real_complex_nonconformant
in the module Maux_wrk
to zcopy
does not lead to a similar conclusion requiring an explicit interface.