Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28463 Discussions

Can't pass derived types thru a subroutine call?

WSinc
New Contributor I
308 Views
This simple example does not work.
I get an error #6633 for all three arguments.
Says the types don't match.

Am I doing something wrong? This seems pretty obvious.
Maybe "len" should not be a component name, but it doesn't flag that.
[bash]SUBROUTINE TESTMUL()
type series
integer(2) st
integer(2) len
real(4) s(0:9)
end type series
type (series):: a,b,c
a%len=3
b%len=4
call xmul(a,b,c)
print *,c
end

subroutine xmul(x,y,z)
type series
integer(2) st
integer(2) len
real(4) s(0:9)
end type series
type(series) :: x,y,z
z%len=x%len+y%len
end
[/bash]
0 Kudos
9 Replies
WSinc
New Contributor I
308 Views
BTW, changing the construct from LEN to something else did not make any difference.
0 Kudos
Paul_Curtis
Valued Contributor I
308 Views
create a module with both subroutines, and define your UDT in one place only as module-local, and hence accessible to all items contained within the module. subroutine xmul() also needs to have its z argument delcared as INTENT(OUT) since it is modified,

SUBROUTINE XMUL (x,y,z)
IMPLICIT NONE
TYPE(series), INTENT(IN) :: x,y
TYPE(series), INTENT(OUT) :: z
0 Kudos
mecej4
Honored Contributor III
308 Views
This seems to be a frequent question. Metcalf, Reid and Cohen's book, 'Fortran 95/2003 Explained' makes the rule clear, but the Fortran Standard could have made the rule a little less obscure.

Different declarations of a TYPE, even if the declarations are identical, do not create argument-compatible types (with few exceptions). That is why it is necessary to create a single definition, in a module if necessary, and USE that definition whereever it is needed.

Section 5.1.1.1 of the standard says:

8 Where a data entity is declared explicitly using the TYPE type specifier, the specified derived type shall
9 have been defined previously in the scoping unit or be accessible there by use or host association.
0 Kudos
mecej4
Honored Contributor III
308 Views
Cautionary note about:

subroutine xmul() also needs to have its z argument delcared as INTENT(OUT) since it is modified...

I suggest that INTENT(IN OUT), or the default, which is almost equivalent (see #7 below), be used for array and derived type arguments, because the language rules stipulate that if INTENT(OUT) is specified, assignment to one or more array element of derived typecomponent makes the other elements and/or components become undefined, except for components that have default initialization specified. Not every compiler behaves in such a way as to make this evident, but it is a source of hard-to-detect bugs.
0 Kudos
WSinc
New Contributor I
308 Views
The INTENT statements didn't make any difference.

Unfortunately, I can't put all the routines in one module,
because I am trying to write a package that has a whole bunch of operations on this type.

For example, I wanted to have add, subrtract, and divide as well as multiply, and
then there are all the possible operations using those as well.

So I would have to put dozens of them in the same module. This removes that flexibility of being able to
compile different routines separately from each other, and in different orders.

I'm wondering why the interface chacker doesn't liike this usage,
it seems pretty basic to me.

Maybe abandoning derived types is the only practical option left.
0 Kudos
mecej4
Honored Contributor III
308 Views
Unfortunately, I can't put all the routines in one module

You do not need to put routines into the module -- only the type definitions.

Similarly, for routines for which the language requires explicit interfaces, you can put the interfaces in a module that is USEd wherever the interfaces are needed. There is a USE xxx, ONLY : statement, and a renaming facility that are useful here.

Maybe abandoning derived types is the only practical option left

No need for such extreme measures. The rules on type compatibility and interfaces serve to dampen exuberant use of derived types that may lead to impossible-to-compile code.

There is always a need for compromise between richness in language features and the difficulty of writing compilers that are able to compile these features and also produce efficient code. The restrictions reflect the specific compromises chosen by the standards committee. Most of us are not aware of the complex arguments behind the language rules, and may feel at times that some specific rule is arbitrary. It would be incorrect to conclude from the relative inaccessibility of these arguments that they do not exist.

0 Kudos
Steven_L_Intel1
Employee
308 Views
Quoting mecej4
I recommend that INTENT(IN OUT), which is the default, be used for array and derived type arguments, because the language rules stipulate that if INTENT(OUT) is specified, assignment to one or more array element of derived typecomponent makes the other elements and/or components become undefined. Not every compiler behaves in such a way as to make this evident, but it is a source of hard-to-detect bugs.

The default is not INTENT(IN OUT), though the difference is subtle. The standard says:

INTENT (INOUT) is not equivalent to omitting the INTENT attribute. The argument corresponding to an INTENT (INOUT) dummy argument always shall be definable, while an argument corresponding to a dummy argument without an INTENT attribute need be definable only if the dummy argument is actually redefined.

INTENT(OUT) makes the entire argument undefined on procedure entry, other than derived type components whose type has component initializers. This includes deallocation of allocatable arrays.

0 Kudos
IanH
Honored Contributor II
308 Views
An alternative to putting the type definitions in a module (which is probably the best way to go) would be to make your type a sequence type. This says to the compiler that it is the type, kind and order of the components in the definition that is important, and not the type or component names.

[fortran]SUBROUTINE TESTMUL() 
type series
sequence
integer(2) st
integer(2) len
real(4) s(0:9)
end type series
type (series):: a,b,c
a%len=3
b%len=4
call xmul(a,b,c)
print *,c
END

SUBROUTINE xmul(x,y,z)
type series
sequence
integer(2) st
integer(2) len
real(4) s(0:9)
end type series
type(series) :: x,y,z
z%len=x%len+y%len
END
[/fortran]

The sequence statement also has implications for the layout of the type in memory, because it tells the compiler that the layout must be compatible with the layout of variables in common blocks. This additional constraint on the compiler may result in slower code.
0 Kudos
WSinc
New Contributor I
308 Views
This seems like a good compromise.
Actually, I also looked at using STRUCTURE and RECORD, and it works fine with no problems.

But I realize that somehow this has become obsolete. I was wondering why it shouldn't be kept
around, since it solves the problems regarding structured record types.

In my case, the variables are actually record types.

Actually, the SEQUENCE entry solved the problem, it compiled with no errors.
The order of the entries seems to make a big difference, and that is why it wouldn't compile previously.

Yours; Bill S.
0 Kudos
Reply