Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Passing derived data types -- module works, but not explicit interface

Status
Not open for further replies.

NickFort

Technical User
Jun 10, 2010
113
Hi there,

I'm just playing around with derived data types, and so I made some functions to see how to pass them to different program units. So, for example, I define a type "vector", which has an "x" and a "y" component, which I pass to a function which simply adds the "x" and the "y" and outputs that.

So, I have the following for the driver program:

Code:
program test_derived

implicit none

interface
	real function addthevecs(myvec)
	implicit none
	type :: vector
		real :: x
		real :: y
	end type
	type(vector) :: myvec
	end function
end interface

type :: vector
	real :: x
	real :: y
end type

type(vector) :: myvec
real :: mysum

myvec%x = 3.
myvec%y = 4.

mysum = addthevecs(myvec)

print *, mysum

end program

and this as the function "addthevecs":

Code:
real function addthevecs(myvec)

implicit none

type :: vector
	real :: x
	real :: y
end type

type(vector) :: myvec

addthevecs = myvec%x + myvec%y

end function

Having provided an explicit interface, I would expect the above to compile and run, but it doesn't. In gfortran, I get the following error:

Code:
>> gfortran test_derived.f95 addthevecs.f95 -o test
test_derived.f95:27.19:

mysum = addthevecs(myvec)
                   1
Error: Type mismatch in argument 'myvec' at (1); passed TYPE(vector) to TYPE(vector)

g95 gives more or less the same information:

Code:
>> g95 test_derived.f95 addthevecs.f95 -o test
In file test_derived.f95:27

mysum = addthevecs(myvec)
                   1
Error: Type mismatch in parameter 'myvec' at (1). TYPE(vector) is not the same type between formal/actual

However, when I put the definition of the derived type in a module "typemod", it compiles and runs fine:

Code:
module typemod

type :: vector
	real :: x
	real :: y
end type

end module

Code:
program test_derived

use typemod

implicit none

type(vector) :: myvec
real :: mysum, addthevecs

myvec%x = 3.
myvec%y = 4.

mysum = addthevecs(myvec)

print *, mysum

end program

Code:
real function addthevecs(myvec)

use typemod

implicit none
type(vector) :: myvec

addthevecs = myvec%x + myvec%y

end function

Now, I would expect both the explicit interface and the module approach to work, but only the latter does. Why is this? Or have I done something wrong with the explicit interface?

Thanks!
NickFort

--------------------------------------
Background: Chemical engineer, familiar mostly with MATLAB, but now branching out into real programming.
 
There are several approaches possible:
1. Declare compound datatypes and operations on them (i.e. function/subroutines in the same module:
test_vectors.f95
Code:
[COLOR=#a020f0]module[/color] my_vectors
  [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]

  [COLOR=#2e8b57][b]type[/b][/color] vector
[COLOR=#2e8b57][b]      real[/b][/color] :: x
[COLOR=#2e8b57][b]      real[/b][/color] :: y
  [COLOR=#2e8b57][b]end type[/b][/color] vector

[COLOR=#a020f0]contains[/color] 
[COLOR=#2e8b57][b]  real[/b][/color] [COLOR=#a020f0]function[/color] addthevecs(myvec)
    [COLOR=#2e8b57][b]type[/b][/color](vector), [COLOR=#2e8b57][b]intent[/b][/color]([COLOR=#2e8b57][b]in[/b][/color]) :: myvec
    addthevecs [COLOR=#804040][b]=[/b][/color] myvec%x [COLOR=#804040][b]+[/b][/color] myvec%y
  [COLOR=#a020f0]end function[/color] addthevecs

[COLOR=#a020f0]end module[/color] my_vectors

[COLOR=#a020f0]program[/color] test_derived
  [COLOR=#a020f0]use[/color] my_vectors
  [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]

  [COLOR=#2e8b57][b]type[/b][/color](vector) :: myvec
[COLOR=#2e8b57][b]  real[/b][/color] :: mysum

  myvec%x [COLOR=#804040][b]=[/b][/color] [COLOR=#ff00ff]3[/color].
  myvec%y [COLOR=#804040][b]=[/b][/color] [COLOR=#ff00ff]4[/color].

  mysum [COLOR=#804040][b]=[/b][/color] addthevecs(myvec)

  [COLOR=#804040][b]print[/b][/color] [COLOR=#804040][b]*[/b][/color], [COLOR=#ff00ff]'myvec = ('[/color], myvec%x, [COLOR=#ff00ff]','[/color], myvec%y, [COLOR=#ff00ff]')'[/color]  
  [COLOR=#804040][b]print[/b][/color] [COLOR=#804040][b]*[/b][/color], [COLOR=#ff00ff]'mysum = '[/color], mysum

[COLOR=#a020f0]end program[/color]
Compilation & Output:
Code:
$ g95 test_vectors.f95 -o test_vectors

$ test_vectors
 myvec = ( 3. , 4. )
 mysum =  7.

2. Declare compound datatypes in one module and use that module in all source files:
test_vectors2.f95
Code:
[COLOR=#a020f0]module[/color] my_vectors
  [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]

  [COLOR=#2e8b57][b]type[/b][/color] vector
[COLOR=#2e8b57][b]      real[/b][/color] :: x
[COLOR=#2e8b57][b]      real[/b][/color] :: y
  [COLOR=#2e8b57][b]end type[/b][/color] vector

[COLOR=#a020f0]end module[/color] my_vectors

[COLOR=#a020f0]program[/color] test_derived
  [COLOR=#a020f0]use[/color] my_vectors
  [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]

  [COLOR=#2e8b57][b]type[/b][/color](vector) :: myvec
[COLOR=#2e8b57][b]  real[/b][/color] :: mysum, addthevecs

  myvec%x [COLOR=#804040][b]=[/b][/color] [COLOR=#ff00ff]3[/color].
  myvec%y [COLOR=#804040][b]=[/b][/color] [COLOR=#ff00ff]4[/color].

  mysum [COLOR=#804040][b]=[/b][/color] addthevecs(myvec)

  [COLOR=#804040][b]print[/b][/color] [COLOR=#804040][b]*[/b][/color], [COLOR=#ff00ff]'myvec = ('[/color], myvec%x, [COLOR=#ff00ff]','[/color], myvec%y, [COLOR=#ff00ff]')'[/color]  
  [COLOR=#804040][b]print[/b][/color] [COLOR=#804040][b]*[/b][/color], [COLOR=#ff00ff]'mysum = '[/color], mysum

[COLOR=#a020f0]end program[/color]
addthevecs.f95
Code:
[COLOR=#2e8b57][b]real[/b][/color] [COLOR=#a020f0]function[/color] addthevecs(myvec)
  [COLOR=#a020f0]use[/color] my_vectors
  [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]  
  [COLOR=#2e8b57][b]type[/b][/color](vector), [COLOR=#2e8b57][b]intent[/b][/color]([COLOR=#2e8b57][b]in[/b][/color]) :: myvec
  addthevecs [COLOR=#804040][b]=[/b][/color] myvec%x [COLOR=#804040][b]+[/b][/color] myvec%y
[COLOR=#a020f0]end function[/color]
Compilation & Output:
Code:
$ g95 test_vectors2.f95 addthevecs.f95  -o test_vectors2

$ test_vectors2
 myvec = ( 3. , 4. )
 mysum =  7.

3. Declare your compound datatype in every source (without using module):
addthevecs2.f95
Code:
[COLOR=#2e8b57][b]real[/b][/color] [COLOR=#a020f0]function[/color] addthevecs(myvec)
  [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]  
  [COLOR=#2e8b57][b]type[/b][/color] vector
[COLOR=#2e8b57][b]      real[/b][/color] :: x
[COLOR=#2e8b57][b]      real[/b][/color] :: y
  [COLOR=#2e8b57][b]end type[/b][/color] vector
  [COLOR=#2e8b57][b]type[/b][/color](vector), [COLOR=#2e8b57][b]intent[/b][/color]([COLOR=#2e8b57][b]in[/b][/color]) :: myvec
  addthevecs [COLOR=#804040][b]=[/b][/color] myvec%x [COLOR=#804040][b]+[/b][/color] myvec%y
[COLOR=#a020f0]end function[/color]
Compilation & Output:
Code:
$ g95 test_vectors2.f95 addthevecs2.f95  -o test_vectors21

$ test_vectors21
 myvec = ( 3. , 4. )
 mysum =  7.
 
Hmmm, OK, I can get that to work as well.

But what I'd like to know is why the explicit interface doesn't work. In my original code, if I remove the interface and add "addthevecs" to the real declaration, it works fine. I just thought that, if anything, an explicit interface would make the compiler's job easier.

Without using derived data types, I've tried it, and you can use either the explicit or implicit interface.

So, with an explicit interface:

Code:
program test_expimp

implicit none

interface
	real function myfoo(num2)
	implicit none
	real, intent(in) :: num2
	end function
end interface

real :: num1, num2

num2 = 3.
num1 = myfoo(num2)

print *, num2, num1

end program

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

real function myfoo(num2)

implicit none

real, intent(in) :: num2

myfoo = 2.*num2

end function

With an implicit interface:

Code:
program test_expimp

implicit none

real :: num1, num2, myfoo

num2 = 3.
num1 = myfoo(num2)

print *, num2, num1

end program

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1

real function myfoo(num2)

implicit none

real, intent(in) :: num2

myfoo = 2.*num2

end function

Both of these work equally well, but it appears not to be the case with derived data types.

Most puzzling...

By the way, on a side note, how do you get the syntax colouring?


--------------------------------------
Background: Chemical engineer, familiar mostly with MATLAB, but now branching out into real programming.
 
If I try only to compile your program (without linking) I get the same error as you
Code:
$ g95  -c test_derived.f95
In file test_derived.f95:27

mysum = addthevecs(myvec)
                   1
Error: Type mismatch in parameter 'myvec' at (1).  TYPE(vector) is not the same type between formal/actual

IMHO: The problem is that you defined the same type i.e. vector more than once in the same scope, i.e. in scope of the main program. When you define the same type more than once, than the compiler says that the type is not the same.

But, when you define the type vector only once in the module and use the module in your main program and in the function, then it works.
test_derived_mod.f95
Code:
[COLOR=#a020f0]module[/color] my_vectors
[COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]
[COLOR=#2e8b57][b]type[/b][/color] :: vector
[COLOR=#2e8b57][b]    real[/b][/color] :: x
[COLOR=#2e8b57][b]    real[/b][/color] :: y
[COLOR=#2e8b57][b]end type[/b][/color]
[COLOR=#a020f0]end module[/color] my_vectors

[COLOR=#a020f0]program[/color] test_derived
[COLOR=#a020f0]use[/color] my_vectors
[COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]

[COLOR=#a020f0]interface[/color]
[COLOR=#2e8b57][b]    real[/b][/color] [COLOR=#a020f0]function[/color] addthevecs(myvec)
    [COLOR=#a020f0]use[/color] my_vectors
    [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]
    [COLOR=#2e8b57][b]type[/b][/color](vector) :: myvec
    [COLOR=#a020f0]end function[/color]
[COLOR=#a020f0]end interface[/color]

[COLOR=#2e8b57][b]type[/b][/color](vector) :: myvec
[COLOR=#2e8b57][b]real[/b][/color] :: mysum

myvec%x [COLOR=#804040][b]=[/b][/color] [COLOR=#ff00ff]3[/color].
myvec%y [COLOR=#804040][b]=[/b][/color] [COLOR=#ff00ff]4[/color].

mysum [COLOR=#804040][b]=[/b][/color] addthevecs(myvec)

[COLOR=#804040][b]print[/b][/color] [COLOR=#804040][b]*[/b][/color], mysum

[COLOR=#a020f0]end program[/color]
It compiles and links with both function definitions (addthevecs.f95 and addthevecs2.f95):
Code:
$ g95  test_derived_mod.f95 addthevecs.f95 -o test_derived_mod

$ test_derived_mod
 7.

$ g95  test_derived_mod.f95 addthevecs2.f95 -o test_derived_mod

$ test_derived_mod
 7.

To avoid similar problesm use the modules

By the way, on a side note, how do you get the syntax colouring?
I'm using the procedure from here:
 
Once again, thanks, Mikrom. I vastly prefer the module way of doing things, and would naturally lean towards that -- I was just playing around with different options to learn a bit more about Fortran. Cool, that seems like mystery solved then. :)

--------------------------------------
Background: Chemical engineer, familiar mostly with MATLAB, but now branching out into real programming.
 
It is failing because there are two definitions of vector: one at top level and one inside the routine. Pascal has a similar problem. In the cases where it compiles, there is only one definition. Basically the rule is define once, use many times.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top