Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Invocation of overridden procedure on an abstract parent component

323 views
Skip to first unread message

Damian

unread,
Feb 26, 2010, 5:12:10 PM2/26/10
to knm...@sandia.gov, jim...@ca.ibm.com
If an extended type overrides a type-bound procedure of its abstract
parent, can it explicitly invoke the parent's version on of the
procedure on the parent component? The code below works if I delete
the "abstract" attribute from the parent type. With the abstract
attribute, I get the error below from gfortran 4.5.0 20100103
(experimental) [trunk revision 155591]:

$ 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'

Tobias Burnus

unread,
Feb 26, 2010, 6:57:17 PM2/26/10
to
Damian wrote:
> If an extended type overrides a type-bound procedure of its abstract
> parent, can it explicitly invoke the parent's version on of the
> procedure on the parent component?

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

Tobias Burnus

unread,
Feb 27, 2010, 10:27:37 AM2/27/10
to
Am 27.02.2010 00:57, schrieb Tobias Burnus:
> Damian wrote:
>> If an extended type overrides a type-bound procedure of its abstract
>> parent, can it explicitly invoke the parent's version on of the
>> procedure on the parent component?
>
> 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).

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" ...

Damian

unread,
Feb 27, 2010, 7:51:10 PM2/27/10
to jim...@ca.ibm.com, knm...@sandia.gov, bur...@net-b.de

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

Ian Harvey

unread,
Mar 5, 2010, 12:18:04 AM3/5/10
to
On 28/02/2010 11:51 AM, Damian wrote:
> ...

> 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?

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

0 new messages