(j3.2006) Parent component of extension of abstract type
Fri Nov 13 00:48:30 EST 2015
Theis code appears to be OK because subroutine Implementation doesn't
call this%parent%nondeferred_tbp. Doing so would once again fall afoul
of constraint C611, which requires <data-ref> to be polymorphic if its
type (i.e., the type of this%parent) is abstract.
If we do any extending in this area, to allow <data-ref> to be
nonpolymorphic in some cases where its type is abstract, we can and
should prohibit to invoke deferred bindings. Whether we prohibit to
invoke nondeferred bindings can be decided if we ever get that far.
As I mentioned in my response to Malcolm, the real danger is in allowing
a polymorphic object to have an abstract dynamic type, or allowing to
invoke a deferred binding by way of an object of abstract type (no
matter whether it's the declared or dynamic type).
We can allow more stuff to be done with objects of abstract type and
still prevent that at compile time. We can allow to instantiate
nonpolymorphic objects, and nonpolymorphic components in addition to
parent components. We can allow to reference objects of abstract type.
To keep the safety of not invoking deferred bindings, we need to require
<data-ref> in a <procedure-designator> is polymorphic if its type is
abstract, at least if the binding is deferred,
<expr> is polymorphic if its type is abstract, and it's the
<data-target> in a pointer assignment, and the <data-pointer-object> is
polymorphic (this prevents a polymorphic object from having an abstract
dynamic type), and
<source-expr> is polymorphic if its type is abstract and the
<allocate-object> is polymorphic (this also prevents a polymorphic
object from having an abstract dynamic type).
What we have done requires these three things, but prevents too much by
being too broad, i.e., <data-ref> is polymorphic if its type is
abstract, period, end of story.
On Thu, 2015-11-12 at 21:08 -0800, Damian Rouson wrote:
> > On Nov 12, 2015, at 2:10 PM, Tom Clune <Thomas.L.Clune at nasa.gov>
> > wrote:
> > Sorry - just realized that I misworded my final point.
> > I meant to say it would be nice if one could invoke the non-deferred
> > methods in an abstract parent.
> Unless, I?m misunderstanding the above sentence, this is already
> allowed. In the code below, for example, I invoke a non-deferred
> type-bound procedure on an abstract parent at line 44 and also
> arguably at lines 18 and 46.
> > But, the non-deferred methods might invoke a deferred method ?
> This is a common practice at the heart of several OO design patterns.
> The Template Method pattern, for example, involves specifying the
> steps of an algorithm in a series of deferred bindings and then
> writing a non-deferred type-bound procedure that successively invokes
> the deferred bindings. The nondeferred_tbp subroutine below is
> essentially a degenerate template method with only one step in the
> algorithm it encapsulates.
> The Cray, Intel, Portland Group, and GNU compilers all accept the code
> below so again I?m wondering what the constraint is and whether
> they?re accepting non-conforming code.
> 1 module parent_module
> 2 implicit none
> 3 type, abstract :: parent
> 4 contains
> 5 procedure(abstract_interface), deferred :: deferred_binding
> 6 procedure :: nondeferred_tbp
> 7 end type
> 9 abstract interface
> 10 subroutine abstract_interface(this)
> 11 import parent
> 12 class(parent) :: this
> 13 end subroutine
> 14 end interface
> 15 contains
> 16 subroutine nondeferred_tbp(this)
> 17 class(parent) :: this
> 18 call this%deferred_binding
> 19 end subroutine
> 20 end module
> 22 module child_module
> 23 use parent_module, only : parent
> 24 implicit none
> 25 type, extends(parent) :: child
> 26 contains
> 27 procedure :: deferred_binding => implementation
> 28 end type
> 29 contains
> 30 subroutine implementation(this)
> 31 class(child) :: this
> 32 call this%nondeferred_tbp
> 33 end subroutine
> 34 end module
> 36 program main
> 37 use parent_module, only : parent
> 38 use child_module, only : child
> 39 implicit none
> 40 class(parent), allocatable :: nothing
> 41 type(child) :: thing
> 42 allocate(nothing,source=thing)
> 43 call nothing%deferred_binding
> 44 call nothing%nondeferred_tbp
> 45 call thing%deferred_binding
> 46 call thing%nondeferred_tbp
> 47 end program
More information about the J3