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

Accessing type-bound procedures of parent types

20 views
Skip to first unread message

Rich Townsend

unread,
Feb 10, 2011, 11:01:33 PM2/10/11
to
Hi folks --

I've run into a coding conundrum with F03. Given a derived type ext_t which is
an extension of a parent derived type base_t, is there any way to access a type-
bound procedure of base_t if this procedure has been overriden in the definition
of ext_t?

At first glance, this would seem to do the trick:

type(ext_t) :: t

call t%base_t%some_proc(...)

However, t%base_t has type base_t, which isn't what I want -- I want to call the
base_t implementation of some_proc() with a variable of type ext_t.

So, can this be done? Or, am I misunderstanding the general paradigm for the F03
type extension capabilities?

Many thanks,

Rich


Richard Maine

unread,
Feb 11, 2011, 12:56:56 AM2/11/11
to
Rich Townsend <mylas...@astro.wisc.edu> wrote:

I'm a little confused by your description. I'm not sure how much of that
confusion is because of imprecision in the description and how much is
in my poor reading. If you want to call the procedure bound to the type
base_t, then that would be, as you write,

call t%base_t%some_proc(...)

If you want to call the overriding version of the procedure from ext_t,
that would be

call t%some_proc(...)

My best guess is that the problem lies in what you loosely describe as
"with a variable of type ext_t". What do you mean by calling a procedure
"with a variable"? That's not precise Fortran terminology for anything.
Perhaps making the terminology more precise might help lead to the
answer.

In particular, think maybe you are referring to passing the variable of
type ext_t as an actual argument to the procedure. If that's the case,
then you are wanting to use one variable to determine what procedure to
call, and a different variable to pass as an actual argument. One of
those variables happens to be a subobject of the other, but I don't see
that as a particularly relevant point; in fact, that might be what is
misleading you. Let's ignore any question of there being a relationship
between the variables and just focus on the fact that there are two
separate variables involved.

I'm betting that your problem lies in using a passed-object dummy
argument. Passed-object dummy arguments are handy in reducing redundant
verbosity when the variable whose type binding determines the procedure
to call is also used an argument of the procedure. But its whole point
is that the two variables are the same. If the two variables might not
be the same, then you don't want a passed-object dummy. Just pass the
arguments the "regular old way". So you'd have something like

call t%some_proc(t%base_t,...)

if I got it straight. Of course, maybe I completely misunderstood the
question.

--
Richard Maine | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle | -- Mark Twain

Mark LeAir

unread,
Feb 11, 2011, 1:17:54 AM2/11/11
to
Hi Rich,

I'm not entirely sure why you would need to pass in ext_t into a
procedure with a base_t pass argument unless the procedure does
something special with components only found in ext_t (e.g., there's a
select type statement in the base_t procedure). Anyway...

Assuming you have the liberty to modify "some_proc", consider
declaring it NOPASS. Then you can add the ext_t variable in the
"argument slot" where the pass argument would normally be passed. For
example:

type base_t
contains
procedure, nopass :: some_proc
end type

...

type(ext_t) :: t
call t%base_t%some_proc(t)


Below is a simple example and run:

module mod

type base_t
contains
procedure, nopass :: some_proc => baseproc
end type

type, extends(base_t) :: ext_t
contains
procedure, nopass :: some_proc => extproc
end type

contains

subroutine baseproc(this)
class(base_t) :: this
select type(this)
type is(base_t)
print *, 'baseproc BASE T'
type is (ext_t)
print *, 'baseproc EXT T'
end select
end subroutine


subroutine extproc(this)
class(base_t) :: this
print *, 'unexpected extproc called'
end subroutine


end module


program p
use mod
type(ext_t) :: t

call t%base_t%some_proc(t)

end program

% pgf90 -V prg.f90

pgf90 11.1-0 64-bit target on x86-64 Linux -tp penryn
Copyright 1989-2000, The Portland Group, Inc. All Rights Reserved.
Copyright 2000-2011, STMicroelectronics, Inc. All Rights Reserved.
PGF90/x86-64 Linux 11.1-0
Copyright 1989-2000, The Portland Group, Inc. All Rights Reserved.
Copyright 2000-2011, STMicroelectronics, Inc. All Rights Reserved.
PGF90/x86-64 Linux 11.1-0
Copyright 1989-2000, The Portland Group, Inc. All Rights Reserved.
Copyright 2000-2011, STMicroelectronics, Inc. All Rights Reserved.

% a.out
baseproc EXT T


As expected, the program prints "baseproc EXT T", verifying that the
base_t some_proc implementation received an ext_t argument.
-Mark

Rich Townsend

unread,
Feb 11, 2011, 1:23:10 AM2/11/11
to

No, indeed you more or less correctly surmised what I was getting at. I want
to use the type of t%base_t to determine the procedure to call, but I want t
itself (and not t%base_t) to be associated with the passed-object dummy
argument.

In C++, this can be done by prepending a class name -- e.g.,
base_t::some_proc. In Java, one can use the superclass constructor super().
But from my understanding of what you've written, there is no straighforward
way in F03 to access type-bound procedures of a parent type if they are
overriden in the child type.

I guess the workaround is to provide an additional name for the procedure
that's going to be overridden. E.g., in the definition of base_t:

type :: base_t
contains
procedure :: some_proc
procedure :: base_t_some_proc => some_proc
end type base_t

Then, even when some_proc is overridden in an extension to base_t, it will
still be accessible via base_t_some_proc. I hope. ;)

Thanks for your insights -- much appreciated as always.

cheers,

Rich


Richard Maine

unread,
Feb 11, 2011, 1:28:24 AM2/11/11
to
Rich Townsend <mylas...@astro.wisc.edu> wrote:

> But from my understanding of what you've written, there is no straighforward
> way in F03 to access type-bound procedures of a parent type if they are
> overriden in the child type.

Yes there is. I showed how. My example did access the type-bound
procedure of the parent type, even though it was overridden in the child
type. Literally and exactly. What you can't do is then pass something
other than the parent object as a passed-object dummy argument.

The solution is not to specify that the procedure uses a passed-object
dummy.

Rich Townsend

unread,
Feb 11, 2011, 1:33:00 AM2/11/11
to
nos...@see.signature (Richard Maine) wrote:

> Rich Townsend <mylas...@astro.wisc.edu> wrote:
>
>> But from my understanding of what you've written, there is no straighforward
>> way in F03 to access type-bound procedures of a parent type if they are
>> overriden in the child type.
>
> Yes there is. I showed how. My example did access the type-bound
> procedure of the parent type, even though it was overridden in the child
> type. Literally and exactly. What you can't do is then pass something
> other than the parent object as a passed-object dummy argument.
>
> The solution is not to specify that the procedure uses a passed-object
> dummy.
>

I think I understand. But shouldn't your example read:

call t%base_t%some_proc(t, ...)

(where some_proc is declared as NOPASS)?

cheers,

Rich


Richard Maine

unread,
Feb 11, 2011, 1:34:40 AM2/11/11
to
Mark LeAir <leai...@gmail.com> wrote:

> Assuming you have the liberty to modify "some_proc", consider
> declaring it NOPASS. Then you can add the ext_t variable in the
> "argument slot" where the pass argument would normally be passed.

That's basically the same suggestion I made (though you nicely fleshed
it out as a working example), except I might note that I find the
description of it as modifying some_proc slightly misleading in a way
that makes it sound more intrusive than it is. You don't have to touch
the procedure - just the type binding of it. Of course, your some_proc
is actually the binding, so I suppose the description is technically
accurate.

Richard Maine

unread,
Feb 11, 2011, 1:41:09 AM2/11/11
to
Rich Townsend <mylas...@astro.wisc.edu> wrote:

> I think I understand. But shouldn't your example read:
>
> call t%base_t%some_proc(t, ...)
>
> (where some_proc is declared as NOPASS)?

Yes, possibly. I briefly thought about that form, but concluded it was
the other way around that you wanted. Guess I still got it backwards.
Either form makes at least some sense, depending which you want. See
Mark's nice example; a working example beats my vague description.

Rich Townsend

unread,
Feb 11, 2011, 1:47:33 AM2/11/11
to
Mark LeAir <leai...@gmail.com> wrote:

> Hi Rich,
>
> I'm not entirely sure why you would need to pass in ext_t into a
> procedure with a base_t pass argument unless the procedure does
> something special with components only found in ext_t (e.g., there's a
> select type statement in the base_t procedure). Anyway...
>

Thanks for your example code -- much appreciated!

BTW, to give some context: there are no select type statements in the base_t
procedure, but it does call other type-bound procedures --- and I want the
type of the passed-object dummy to be used to determine which tbp to call.

Thanks again,

Rich

> Assuming you have the liberty to modify "some_proc", consider
> declaring it NOPASS. Then you can add the ext_t variable in the
> "argument slot" where the pass argument would normally be passed. For
> example:
>
> type base_t
> contains
> procedure, nopass :: some_proc
> end type
>

> ....

Rich Townsend

unread,
Feb 11, 2011, 2:55:45 AM2/11/11
to
Mark LeAir <leai...@gmail.com> wrote:

> HiáRich,á
> á
> I'mánotáentirelyásureáwhyáyouáwouldáneedátoápassáináext_táintoáaá
> procedureáwitháaábase_tápassáargumentáunlessátheáprocedureádoesá
> somethingáspecialáwithácomponentsáonlyáfoundáináext_tá(e.g.,áthere'sáaá
> selectátypeástatementáinátheábase_táprocedure).áAnyway...á
> á
> Assumingáyouáhaveátheálibertyátoámodifyá"some_proc",áconsiderá
> declaringáitáNOPASS.áThenáyouácanáaddátheáext_távariableáinátheá
> "argumentáslot"áwhereátheápassáargumentáwouldánormallyábeápassed.áForá
> example:á
> á
> typeábase_tá
> containsá
> procedure,ánopassá::ásome_procá
> endátypeá
> á
> ....á
> á
> type(ext_t)á::átá
> callát%base_t%some_proc(t)á
> á
> á

I wonder whether one can have one's cake and eat it. Here's a modified version
of your code, which gets rid of the type extension stuff, but combines a pass
and nopass version of baseproc under the same generic name some_proc.

module mod

type base_t
contains

procedure, nopass :: baseproc_nopass => baseproc
procedure, pass :: baseproc_pass => baseproc
generic :: some_proc => baseproc_pass, baseproc_nopass


end type

contains

subroutine baseproc(this)
class(base_t) :: this

print *, 'baseproc BASE T'

end subroutine

end module


program p
use mod

type(base_t) :: t

call t%some_proc()
call t%some_proc(t)

end program


This compiles and works on gfortran 4.6.

The Intel compiler spits out a warning:

p.f90(12): warning #8449: The type/rank/keyword signature for this specific
procedure matches another specific procedure that shares the same generic
binding name. [BASEPROC]
subroutine baseproc(this)

..but the code still works.

The NAG compiler, however, refuses to compile:

Error: p.f90, line 17: Ambiguous specific type-bound procedures BASEPROC_NOPASS
and BASEPROC_PASS for type-bound generic SOME_PROC in type BASE_T

I guess it comes down to whether the PASS/NOPASS attribute is relevant in TKR
matching. Could someone (Richard?) comment on this?

Many thanks,

Rich


Ian Harvey

unread,
Feb 11, 2011, 3:51:03 AM2/11/11
to
On 11/02/2011 3:01 PM, Rich Townsend wrote:
> Hi folks --
>
> I've run into a coding conundrum with F03. Given a derived type ext_t which is
> an extension of a parent derived type base_t, is there any way to access a type-
> bound procedure of base_t if this procedure has been overriden in the definition
> of ext_t?

As an alternative to going via the parent component of ext_t, if the
procedure that implements the type bound procedure for the parent type
is accessible you could just call it directly.

TYPE base_t
CONTAINS
PROCEDURE :: some_proc => some_proc_for_base_t
END TYPE base_t

TYPE, EXTENDS(base_t) :: ext_t
CONTAINS
PROCEDURE :: some_proc => some_proc_for_ext_t
END TYPE ext_t


TYPE(ext_t) :: t

! I don't want the extension's behaviour - I want the parents!
CALL some_proc_for_base_t(t, ...)

Janus Weil

unread,
Feb 11, 2011, 5:13:01 AM2/11/11
to
Hi Rich,

without checking what the official Fortran standard says on this
issue, and just using my naive common sense, I'd say that one could
allow such a case, because I can tell by looking at it that the first
call can only be resolved to 'baseproc_pass' and the second one to
'baseproc_nopass'. Of course it doesn't really make a difference here,
since both versions call the same underlying procedure.

However, one may think of cases where it is more problematic, e.g.:


module mod

type base_t
contains
procedure, nopass :: baseproc_nopass => baseproc1
procedure, pass :: baseproc_pass => baseproc2


generic :: some_proc => baseproc_pass, baseproc_nopass
end type

contains

subroutine baseproc1 (this)
class(base_t) :: this
print *, 'baseproc1'
end subroutine

subroutine baseproc2 (this,that)
class(base_t) :: this, that
print *, 'baseproc2'
end subroutine

end module

program p
use mod
type(base_t) :: t

call t%some_proc(t) ! ambiguous!!!
end program


Here, I'd say the call is truly ambiguous. It could either go to
'baseproc1' with NOPASS or 'baseproc2' with PASS. gfortran currently
compiles this without error and prints 'baseproc2', which I think is a
bug. I haven't checked other compilers.

Rich Townsend

unread,
Feb 11, 2011, 11:13:11 AM2/11/11
to

That might be the best way to do things. And one can also do it with passed-
object dummy arguments:

TYPE base_t
CONTAINS
PROCEDURE :: some_proc_for_base_t


PROCEDURE :: some_proc => some_proc_for_base_t
END TYPE base_t

..

TYPE(ext_t) :: t

CALL t%some_proc() ! Calls some_proc_for_ext_t
CALL t%some_proc_for_base_t() ! Calls some_proc_for_base_t

cheers,

Rich


Richard Maine

unread,
Feb 11, 2011, 1:17:00 PM2/11/11
to
Rich Townsend <mylas...@astro.wisc.edu> wrote:

> I guess it comes down to whether the PASS/NOPASS attribute is relevant in TKR
> matching. Could someone (Richard?) comment on this?

Hmm. Off the top of my head, I'd have to admit that I have no clue.
(Feel free to generalizer as strikes your fancy). I don't recall whether
the rules for generics even mention the subject.... checking....

Ok. Yes, the rules certainly mention passed-object dummies. I fact,
darn, the mentions are almost obtrusive in that you have to paw through
all the passed-object dummy stuff before you can see what is being said
about the simpler cases.

Too much bother to quote completely (see 16.2.3 of f2003). I recall that
there are subtle distinctions in the wording of those rules that I never
did manage to understand. I don't at the moment recall what those
distinctions were, but I do recall that there were some. Hmm. Think I
just figured it out - that is I figured out what my confusion was about;
I'm stil confused, but I think I now remember what I'm confused about
(if that makes sense). I don't know why some parts of the rules are
about dummy data arguments, while other parts omit the "data". Yes, I
know what it means for something to be a dummy data argument. What I
don't know is why some of these rules are about data objects and some
aren't.

Anyway, with the caveat that I find these rules pretty hard to read, I
think they say that your code is ok. If nothing else, looks to me like
your case passes the first test (the one about the number of
indistinguishable dummy arguments), since one of your procedures has a
nonoptional, non-passed dummy data object, and the other procedure has
no non-passed dummy data objects at all. 1 does exceed 0.

Mark LeAir

unread,
Feb 11, 2011, 6:26:45 PM2/11/11
to
On Feb 11, 10:17 am, nos...@see.signature (Richard Maine) wrote:

> Rich Townsend <mylastn...@astro.wisc.edu> wrote:
> > I guess it comes down to whether the PASS/NOPASS attribute is relevant in TKR
> > matching. Could someone (Richard?) comment on this?
>
> Hmm. Off the top of my head, I'd have to admit that I have no clue.
> (Feel free to generalizer as strikes your fancy). I don't recall whether
> the rules for generics even mention the subject.... checking....
>

I believe Rich's example is ambiguous when we take a look at the F2003
rules in section 16.2.3 Restrictions on generic declarations

First, let's consider each procedure in the generic set:

procedure, nopass :: baseproc_nopass => baseproc
procedure, pass :: baseproc_pass => baseproc

And the interface for baseproc:

subroutine baseproc(this)
class(base_t) :: this
end subroutine

baseproc_nopass has 1 nonoptional non-pass-object dummy argument.
baseproc_pass has 0 nonoptional non-pass-object dummy arguments (but
one nonoptional pass object dummy argument).

OK, now let's quote a couple supporting definitions from section
16.2.3:

Two dummy arguments are distinguishable if neither is a subroutine and
neither is TKR compatible
(5.1.1.2) with the other.

The effective position of a dummy argument is its position in the
argument list after any passed-object
dummy argument has been removed.


Now, rule 3 (see section 16.2.3 for the other 2 rules):

Within a scoping unit, two procedures that have the same generic name
shall both be subroutines or
both be functions, and ...


(3) at least one of them shall have both
(a) A nonoptional non-passed-object dummy argument at an effective
position such that
either the other procedure has no dummy argument at that effective
position or the
dummy argument at that position is distinguishable with it; and
(b) A nonoptional non-passed-object dummy argument whose name is such
that either
the other procedure has no dummy argument with that name or the dummy
argument
with that name is distinguishable with it.

So, returning to Rich's example, baseproc_nopass and baseproc_pass
satisfy rule 3a because baseproc_pass does not have any non-passed-
object dummies. However, it doesn't satisfy 3b because the
baseproc_nopass "this" is *NOT* distinguishable by the "baseproc_pass"
"this" argument (see the definition for "distinguishable" above -- or
to put it another way, they're the same dummy argument,
"class(base_t) :: this" declared in subroutine baseproc, so they are
not distinguishable).


With that said...

Rich,

You can possibly achieve what you're trying to do by doing away with
the generic type bound procedure and use an "optional" argument (in
addition to a passed-dummy object) with a specific type bound
procedure.

For example,

module mod

type base_t
contains
procedure :: some_proc => baseproc
end type

contains

subroutine baseproc(this,this2)
class(base_t) :: this
class(base_t), optional :: this2

if (present(this2)) then
print *, 'this2 is present'
else
print *, 'this2 is NOT present'
endif
end subroutine

end module

program p
use mod
type(base_t) :: t

call t%some_proc()
call t%some_proc(t)

end program


% pgfortran opt.f90
% a.out
this2 is NOT present
this2 is present


Richard Maine

unread,
Feb 11, 2011, 7:13:36 PM2/11/11
to
Mark LeAir <leai...@gmail.com> wrote:

> On Feb 11, 10:17 am, nos...@see.signature (Richard Maine) wrote:
> > Rich Townsend <mylastn...@astro.wisc.edu> wrote:
> > > I guess it comes down to whether the PASS/NOPASS attribute is relevant
> > > in TKR matching. Could someone (Richard?) comment on this?
> >
> > Hmm. Off the top of my head, I'd have to admit that I have no clue.
> > (Feel free to generalizer as strikes your fancy). I don't recall whether
> > the rules for generics even mention the subject.... checking....
> >
>
> I believe Rich's example is ambiguous when we take a look at the F2003
> rules in section 16.2.3 Restrictions on generic declarations

....


> Now, rule 3 (see section 16.2.3 for the other 2 rules):

Yes. I was unsure of the application of rule 3. But it looks to me like
rule 1 works. That's why I cited it (a bit vaguely, calling it "the
first test" as I didn't want to quote the whole thing). Note that there
is an "or" between those rules; you don't have to satisfy all 3 of them
- just any one. Yes, it is one of those half-page-long sentences that
can be confusing to parse, but the "or" there does mean "(1), (2), or
(3)" even though (1) and (3) are long enough to make it hard to spot
that little word hiding at the end of (2).

Mark LeAir

unread,
Feb 11, 2011, 8:47:19 PM2/11/11
to
On Feb 11, 4:13 pm, nos...@see.signature (Richard Maine) wrote:

Hi Richard,

I agree that Rich's example satisfy rule 1. What threw me off was the
use of semicolons in the F2003 Spec. There is a semicolon at the end
of rule 1b but there's no "and" or "or" after the semicolon. Yet, the
author used an "and" or an "or" after the other semicolons (see the
semicolon at end of rule 2 and rule 3a). Below is the F2003 language:

Within a scoping unit, two procedures that have the same generic name
shall both be subroutines or
both be functions, and

(1) there is a non-passed-object dummy data object in one or the other
of them such that
(a) the number of dummy data objects in one that are nonoptional, are
not passed-object,
and with which that dummy data object is TKR compatible, possibly
including that
dummy data object itself,
exceeds
(b) the number of non-passed-object dummy data objects, both optional
and nonoptional,
in the other that are not distinguishable with that dummy data object;
(2) both have passed-object dummy arguments and the passed-object
dummy arguments are
distinguishable; or


(3) at least one of them shall have both
(a) A nonoptional non-passed-object dummy argument at an effective
position such that
either the other procedure has no dummy argument at that effective
position or the
dummy argument at that position is distinguishable with it; and
(b) A nonoptional non-passed-object dummy argument whose name is such
that either
the other procedure has no dummy argument with that name or the dummy
argument
with that name is distinguishable with it.

Interestingly, my copy of the F2008 spec replaces the semicolons with
commas. In my opinion, the use of commas allows the reader to better
relate the "or" at the end of rule 2 with the comma at the end of rule
1b. Perhaps that's why the authors made that change in the F2008 spec.

-Mark

Richard Maine

unread,
Feb 11, 2011, 9:01:09 PM2/11/11
to
Mark LeAir <leai...@gmail.com> wrote:

> On Feb 11, 4:13 pm, nos...@see.signature (Richard Maine) wrote:

> > Yes, it is one of those half-page-long sentences that
> > can be confusing to parse, but the "or" there does mean "(1), (2), or
> > (3)" even though (1) and (3) are long enough to make it hard to spot
> > that little word hiding at the end of (2).

> What threw me off was the use of semicolons in the F2003 Spec.

> Interestingly, my copy of the F2008 spec replaces the semicolons with


> commas. In my opinion, the use of commas allows the reader to better
> relate the "or" at the end of rule 2 with the comma at the end of rule
> 1b. Perhaps that's why the authors made that change in the F2008 spec.

Not sure. I didn't carefully study the f208 version. I know that the
semicolons are in the f2003 version because they separate list items
that have commas within them. That's the usual grammatical rule for
such. Of course, *FAR* better is to have sentences that aren't so
blasted long and complicated in the first place.

0 new messages