wordy
wordy

Reputation: 559

Procedure inheritance rules in Fortran 2003/2008 for class(*)

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

Answers (1)

francescalus
francescalus

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

Related Questions