Reputation: 559
Consider the following code
module classes
Type AData
end Type
Type A
contains
procedure :: Work
end type
Type, extends(AData) :: BData
end Type
Type, extends(A) :: B
contains
procedure :: Work => Work2
end type
contains
subroutine Work(this, D)
class(A) :: this
class(*) :: D
end subroutine
subroutine Work2(this, D)
class(B) :: this
class(BData) :: D
end subroutine
end module classes
Is this valid? It is accepted by ifort and rejected by gfortran (because of the non-identical classes in the second argument of Work2).
If it is not valid, it seems clearly useful in some instances: with more arguments of different types, descendant procedures would have to have multiple nested "select type" statements to convert the arguments to the expected type. This would be horribly verbose and presumably also less efficient if it is known at compile time what types the arguments will have in the descendant classes (at the expense of losing some compile-time consistency checks). Is there a compiler option to make gfortran accept this construct, or should it be a gcc bug report/feature request?
--Edit--: To be explicit, Gfortran 4.9 trunk gives Error: Argument mismatch for the overriding procedure 'work' at (1): Type mismatch in argument 'd' (CLASS(bdata)/CLASS(*))
ifort (but not gfortran) also allows constructs such as
subroutine Work2(this, D)
class(B) :: this
class(*), target :: D
class(BData), pointer :: B
B=>D
end subroutine
and thus appears to treat class(star) variables as having a "trust me, I know what type it is" tag from the developer. To me this seems very reasonable (if used sparingly), and avoids overheads in select type operations and sometimes very longwinded multiple nested select type statements. The only other valid way to do blind type casting I know is to push things though an external subroutine where there is no type checking on arguments at all (the horrible way for getting round passing aribitrary type arguments in f90).
The desire to override class(star) procedures with other types also arises in basic contexts like minimization libraries where you want to pass in a function and an arbitrary object. Here the developer and specific function implementation always know what type the object is even if the minimizer does not, and so you don't want to have to do a "select type" in your implementation of the function with a class(*) argument.
Upvotes: 2
Views: 984
Reputation: 32366
The type-bound procedure in B
overrides that in A
, and n the Fortran 2008 standard section 4.5.7.3 has
The overriding and overridden type-bound procedures shall satisfy the following conditions.
...
Dummy arguments that correspond by position shall have the same names and characteristics, except for the type of the passed-object dummy arguments.
My reading of this is that D
must be the same type in the two subroutines. So, the smallest change would indeed to have a select type
construct in at least work2
(perhaps having class(Adata)
as the declaration in both subroutines).
However, would the following be viable?
module classes
Type AData
end Type AData
Type A
contains
procedure :: work_adata
generic :: Work => work_adata
end type A
Type, extends(AData) :: BData
end Type BData
Type, extends(A) :: B
contains
procedure :: work_bdata
generic :: work => work_bdata
end type B
contains
subroutine Work_adata(this, D)
class(A) :: this
type(Adata) :: D
end subroutine Work_adata
subroutine Work_bdata(this, D)
class(B) :: this
type(BData) :: D
end subroutine Work_bdata
end module classes
This works around the difficulties caused by the polymorphism of the data classes by using type declarations for the dummies.
Upvotes: 3