Module Type Error

Hello! I’m completely new to Fortran but not to scientific programming nor to compiled languages. I am trying to learn Fortran and playing around with the tutorial at fortran-lang. I’m currently exploring code organization.

I’m trying to implement a module with a single subroutine. Below is the code.

! hello_world.f90
program hello
   use, intrinsic :: iso_fortran_env, only: sp=>real32, dp=>real64
   use mymod, only: printMat => print_matrix
   implicit none

   integer:: nrow, ncol
   integer:: i, j

   real(dp) :: grid(10, 10)

   nrow = 10
   ncol = 10

   grid(:,:) = 0.0_dp

   call printMat(grid)

end program hello

And my module here

! mymod.f90
module mymod
   use, intrinsic :: iso_fortran_env, only: sp=>real32, dp=>real64
   implicit none

   public param1, print_matrix
   real, parameter :: param1 = 10


   subroutine print_matrix(mat)
      real(sp), intent(in):: mat(:,:)

      integer:: i, j, nrow, ncol
      nrow = size(mat, 1)
      ncol = size(mat, 2)

      do i = 1, ncol
         do j = 1, nrow
            print *, mat(j, i)
         end do
      end do

   end subroutine print_matrix

end module mymod

And finally my makefile


main: mymod.o hello_world.o
	$(FC) $(FFLAGS) $^ -o main

hello_world.o: hello_world.f90
	$(FC) -c $(FFLAGS) $<

mymod.o: mymod.f90
	$(FC) -c $(FFLAGS) $<

	rm main *.mod *.o

When I try to compile this I get the following error. I’m not sure what the problem is - I’d appreciate any ideas on what I did wrong here.

   17 |    call printMat(grid)
      |                      1
Error: Type mismatch in argument ‘mat’ at (1); passed REAL(8) to REAL(4)
make: *** [makefile:8: hello_world.o] Error 1

The error is because you are passing a double precision matrix (dp kind) to a function that takes only single precision (sp kind) matrices.

Using matching kinds would solve your problem.

Thanks for the quick reply.

I thought since I had use, intrinsic :: iso_fortran_env, only: sp=>real32, dp=>real64 and I used real(sp) in both files the kinds were the same.

You are correct, you have imported both single and double precision but in the function definition

you are defining the input argument mat as a single precision matrix.
Then in your main program you are defining a double precision matrix called grid

The compiler sees that and raises an error. The simplest thing you can do is change one of the 2 types so that they are both sp or dp

You did not use real(sp) in both files, you declared

I expect this was just a typo, or an oversight. However, in general, and especially for large programming projects with many separate files, you should declare the precisions or kinds in a single place, and USE those declarations everywhere. Then if/when you want to change precisions later, you change just one parameter statement (or one use statement in your case), and your whole program then works with just a recompilation.

You are correct, it was a typo.

And certainly defining it in a single place would be preferably. I wasn’t sure how to do that yet. But I’d like to.

doh! I missed that I had put sp instead of dp. Thanks!

There are many ways to do this. One approach for your little test code is

Then if you want to change KINDs later, you just change that one definition of wp in the module, and that will propagate throughout the rest of your code.

Another point is that the module must always be compiled before the main program. You could specify this in the Makefile as

hello_world.o: mymod.o

This looks a little odd because mymod.o isn’t really needed during the hello_world.f90 compilation, but the mymod.f90 compilation step is necessary, so you can force the correct compilation order by specifying this artificial dependency.

1 Like

Welcome to the forum. As a side note, you could print the matrix, one element per line, using the
format reversion feature of Fortran, illustrated below.

program main
implicit none
integer, parameter :: nrow = 2, ncol = 3
real :: x(nrow, ncol)
integer :: i, j
call random_number(x)
do i = 1, ncol
   do j = 1, nrow
      print*, x(j, i)
   end do
end do
print*,"using format reversion:"
print "(f15.6)", x
end program main

Sample output:

 using format reversion: