$ cat abstract_parent.f03
module parent_module
implicit none
type ,abstract :: parent
contains
procedure :: foo
end type
contains
subroutine foo(this)
class(parent) :: this
print *,'Inside parent foo'
end subroutine
end module
module child_module
use parent_module
implicit none
type ,extends(parent) :: child
contains
procedure :: foo => foo_child
end type
contains
subroutine foo_child(this)
class(child) :: this
print *,'Inside child foo'
call this%parent%foo()
end subroutine
end module
$ $ gfortran -c abstract_parent.f03
abstract_parent.f03:29.13:
call this%parent%foo()
1
Error: Base object for type-bound procedure call at (1) is of ABSTRACT
type 'parent'
I think it can - as long as it is not DEFERRED. The standard is crafted
such that one cannot invoke a type-bound procedure with a deferred
attribute via
C427 (R429) If the type definition contains or inherits (4.5.6.1) a
deferred binding (4.5.4), ABSTRACT shall appear.
Thus, one can never have a dynamic type which has not overridden this
attribute and thus one cannot call this procedure (cf. also NOTE 4.50).
However, I could not find anything, which prohibits calling a
non-deferred type-bound procedure, declared in an abstract type. Neither
in data-ref (R612, R613, C611) nor at the procedure invocation (R1219,
C1223, C1224, Sect. 12.4.5).
Actually, if you do not override a procedure, calling "child%tbp()" and
"child%parent%tbp()" invokes the same procedure with the same arguments
- still gfortran rejects the "child%parent%tbp()" call.
Thus, I think your program is valid. The error probably came about when
trying to prevent calling a deferred procedure, but the checking is too
broad. I will file a bugreport against gfortran.
Thanks for the report!
Tobias
PS: PR see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43193
It helps if one reads correctly R1219 and *then* checks what R611/C611
has. One then realizes that type%parent%tpb() is invalid - as Jim Xia
kindly pointed out to me.
R611 data-ref is part-ref [ % part-ref ] ...
C611 (R611) If the rightmost part-name is of abstract type,
data-ref shall be polymorphic.
Thus, for a valid data-ref: In "something%parent" parent needs to by
polymorphic (or not abstract).
And for the call, one simply appends "% binding-name" to that data-ref:
R1219 procedure designator is [...] or data-ref % binding-name
Therefore, the call is invalid and gfortran handles the constrain correctly.
Sorry for misreading.
Tobias
PS: I think I have misread "binding-name" as "part-ref" yesterday evening.
PPS: My old NAG f95 v5.1 writes "ERROR: PARENT is not of derived type"
which is not quite right - though also not completely wrong either.
While ifort 11.1 even compiles type%parent%deferred_tbp - though it has
an internal error if "procedure(procintf), deferred...". If you wonder
what happens, if you call it? Well, it simply invokes "procintf" ...
So how do I make the rightmost component polymorphic? I tried
changing foo_child to the following:
subroutine foo_child(this)
class(child) :: this
class(parent) ,pointer :: this_parent=>null()
this_parent => this%parent
print *,'Inside child foo'
call this_parent%foo()
end subroutine
With this revision, gfortran 4.5.0 20100103 (experimental) [trunk
revision 155591] terminates with an internal compiler error. IBM XL
Fortran 5.1 gives
bash-3.2$ xlf2003 Final_test.F90
** parent_module === End of Compilation 1 ===
"Final_test.F90", line 27.20: 1514-648 (S) A structure component
reference must be polymorphic if the rightmost component name is of
abstract type.
** child_module === End of Compilation 2 ===
1501-511 Compilation failed for file Final_test.F90.
where line 27 is the pointer assignment "this_parent => this%parent".
Actually, I guess I understand this error. I just can't see a
workaround if I want to invoke a TBP defined by the parent in
situations where that TBP has been overridden by the child. Does
overriding the parent's TBP prevent me from ever using the version
defined in the parent?
Damian
Damian
Did you ever get an answer for this? Being able to access the parent's
procedure from an extended type is useful when the override wants to add
to the behaviour of the parent type. You see this all the time in
windowing frameworks.
The only work arounds I could see were to either put another level in
the class heirarchy that was a concrete class that had the useful stuff
(see proc_b below) or to call the procedure that contains the useful
parent behaviour directly (proc_c), but both these seem Rather Bodgy for
various reasons.
!----------------
! library code
TYPE, ABSTRACT :: top
CONTAINS
PROCEDURE(xxx), DEFERRED :: proc_a
! some useful default behaviour
PROCEDURE :: proc_c => top_c
END TYPE top
! Concrete middle class with useful behaviour
TYPE, EXTENDS(top) :: middle
CONTAINS
! do nothing, empty proc just to make middle concrete
PROCEDURE :: proc_a => dummy_middle_a
! some useful default behaviour
PROCEDURE :: proc_b => middle_b
END TYPE middle
!----------------
! client code
TYPE, EXTENDS(middle) :: bottom
CONTAINS
! useful proc to satisfy deferred procedure in top. Because we've
! extended middle we wouldn't get told off if we forgot this.
PROCEDURE :: proc_a => bottom_a
! calls middle%proc_b and then provides extra behaviour
PROCEDURE :: proc_b => bottom_b
! calls top_c and then provides extra behaviour
PROCEDURE :: proc_c => bottom_c
END TYPE middle
SUBROUTINE bottom_b(obj)
CLASS(Bottom) :: obj
CALL obj%middle%proc_b
! other stuff
END SUBROUTINE bottom_b
SUBROUTINE bottom_c(obj)
CLASS(Bottom) :: obj
CALL top_c(obj)
! other stuff
END SUBROUTINE bottom_c