Is it possible to overload a deferred procedure with a non-polymorphic procedure?
I'd like to create an abstract class (Parent
) with a procedure (foo
) which must be overloaded by every class which extends Parent
. I run into problems when I want to extend again, such that a class (Grandchild
) extends a class (Child
) which extends Parent
.
Since Child is not abstract, its foo (foo_Child
) must be polymorphic. But then Grandchild
inherits foo_Child
, rather than being forced to define foo_Grandchild
. Further, since I don't want foo_Child
to be polymorphic I want to be able to use Child
-specific non-polymorphic functions within foo_Child
.
module test_module
type, abstract :: Parent
contains
procedure(foo_Parent), deferred :: foo
end type
abstract interface
subroutine foo_Parent(this,input)
import Parent
class(Parent), intent(out) :: this
character(*), intent(in) :: input
end subroutine
end interface
type, extends(Parent) :: Child
contains
procedure :: foo => foo_Child
end type
type, extends(Child) :: Grandchild
! Is not required to define foo=>foo_Grandchild.
! This is not the behaviour I want.
end type
interface Child
module procedure new_Child
end interface
contains
function new_Child(input) result(this)
character(*), intent(in) :: input
type(Child) :: this
end function
subroutine foo_Child(this,input)
type(Child), intent(out) :: this ! Fails: 'this' is not polymorphic.
character(*), intent(in) :: input
this = Child(input) ! Fails if type(Child) is replaced by class(Child).
end subroutine
end module
program test
use test_module
end program
To summarise:
Is there any way of making foo_Child
be non-polymorphic but also overload foo_Parent
? Or is there a way of calling non-polymorphic functions (at least Child=Child
assignment with non-polymorphic rhs) in a polymorphic procedure? If not, is there a workaround?
(I don't want to define class(Child)=type(Child)
, but will if it's the only option).
The dummy argument that corresponds to the passed object of a procedure binding must always be polymorphic.
The rules of the language for intrinsic assignment do not permit assignment to a non-allocatable polymorphic object. This is because typically such an assignment would be an error akin to slicing - you would undefine the bits of the object that are declared in the dynamic type of the rhs but not in the declared type of the lhs.
A polymorphic object can be downcast to a non-polymorphic object using SELECT TYPE and a type guard that matches the dynamic type of the object. You can also merrily slice to your hearts content via argument association - a polymorphic actual argument can be associated with a non-polymorphic dummy of the same declared type.
Extensions can be forced to implement a binding by making the parent type abstract and making (or leaving) the binding deferred (as you have already done). In your situation that perhaps requires an additional type in your hierarchy.
Parent (abstract) --> Child (abstract) +-> RealChild (concrete)
|-> GrandChild (concrete)
Child
in the above might simply leave the foo binding deferred, or it may provide a procedure for that binding and then introduce a new deferred binding that RealChild
and GrandChild
need to implement.