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

Overridability of inaccessible bindings and accessibility of overriding bindings

66 views
Skip to first unread message

Ian Harvey

unread,
Sep 27, 2012, 2:46:25 AM9/27/12
to
If I have a private binding in an extensible type that is in a
particular module; I extend that type in another module and in that
extended type I have a binding of the same name as the private binding
in the parent type, does the binding in the extension type override the
binding in the parent type?

For example:

MODULE a
IMPLICIT NONE
PRIVATE
PUBLIC :: proc
TYPE, PUBLIC :: ta
CONTAINS
PROCEDURE, PRIVATE :: binding
END TYPE ta
CONTAINS
SUBROUTINE binding(arg)
CLASS(ta), INTENT(IN) :: arg
PRINT "('ta')"
END SUBROUTINE binding
SUBROUTINE proc(arg)
CLASS(ta), INTENT(IN) :: arg
CALL arg%binding
END SUBROUTINE proc
END MODULE a

MODULE b
USE a
IMPLICIT NONE
PRIVATE
TYPE, PUBLIC, EXTENDS(ta) :: tb
CONTAINS
PROCEDURE :: binding
END TYPE tb
CONTAINS
SUBROUTINE binding(arg)
CLASS(tb), INTENT(IN) :: arg
PRINT "('tb')"
END SUBROUTINE binding
END MODULE

If the answer is yes, which is my guess based on what I've read and what
my compiler seems to do, is the accessibility of the binding in the
extension type influenced at all by the accessibility of the binding in
the parent type? My guess being no - for the above example, objects
with declared type tb have an accessible binding "proc" outside of
module b, as opposed to the situation of objects of declared type ta
outside of module a.

So...

USE a
USE b
CLASS(ta), ALLOCATABLE :: obj
ALLOCATE(tb :: obj)
CALL proc(obj) ! Prints "tb"
! CALL ta%binding ! Illegal
SELECT TYPE (obj)
CLASS IS (tb)
CALL tb%binding ! Ok, prints "tb"
END SELECT
END

And while we are all bound up... F2008 4.5.5 p4

A binding of a type is a type bound procedure (specific or
generic), a generic type-bound interface, or a final
subroutine. These are referred to as specific bindings,
generic bindings, and final bindings respectively.

So given "respectively"...

type bound procedure (specific or generic) =>
specific binding

generic type-bound interface => generic binding

final subroutine => final binding

And given "or" - the term "specific binding" can refer to a "type bound
procedure (generic)"? No potential for confusion there...

Ian Harvey

unread,
Sep 27, 2012, 2:55:17 AM9/27/12
to
On 2012-09-27 4:46 PM, Ian Harvey wrote:
...
> So...
>
> USE a
> USE b
> CLASS(ta), ALLOCATABLE :: obj
> ALLOCATE(tb :: obj)
> CALL proc(obj) ! Prints "tb"

! CALL obj%binding ! Illegal

> SELECT TYPE (obj)
> CLASS IS (tb)

CALL obj%binding ! Ok, prints "tb"

> END SELECT
> END
>

Wolfgang Kilian

unread,
Sep 27, 2012, 4:05:28 AM9/27/12
to
On 09/27/2012 08:46 AM, Ian Harvey wrote:
> If I have a private binding in an extensible type that is in a
> particular module; I extend that type in another module and in that
> extended type I have a binding of the same name as the private binding
> in the parent type, does the binding in the extension type override the
> binding in the parent type?

Coincidence: I ran into exactly the same question last week and almost
posted it here, but sort of convinced myself that the behavior of my
compiler was fine ... but see below:

> [code elided]
>
> If the answer is yes, which is my guess based on what I've read and what
> my compiler seems to do

And my compiler says no.

> is the accessibility of the binding in the
> extension type influenced at all by the accessibility of the binding in
> the parent type? My guess being no - for the above example, objects with
> declared type tb have an accessible binding "proc" outside of module b,
> as opposed to the situation of objects of declared type ta outside of
> module a.
>
> So...
>
> USE a
> USE b
> CLASS(ta), ALLOCATABLE :: obj
> ALLOCATE(tb :: obj)
> CALL proc(obj) ! Prints "tb"
> ! CALL ta%binding ! Illegal
> SELECT TYPE (obj)
> CLASS IS (tb)
> CALL tb%binding ! Ok, prints "tb"
> END SELECT
> END
>
> [...]

Here is my example, which is essentially equivalent (I think, please
correct me if I'm wrong), but the compiler treats it differently:

---------------------------------------------------
module base
implicit none
public

type, abstract :: base_t
contains
procedure, nopass, private :: msg => base_msg
end type base_t

contains

subroutine base_msg ()
print *, "base type"
end subroutine base_msg

subroutine write_msg (t)
class(base_t), intent(in) :: t
call t%msg
end subroutine write_msg

end module base


module implementation
use base
implicit none
public

type, extends (base_t) :: concrete_t
contains
procedure, nopass :: msg => concrete_msg
end type concrete_t

contains

subroutine concrete_msg ()
print *, "concrete type"
end subroutine concrete_msg

end module implementation


program main
use base, only: write_msg
use implementation
implicit none

type(concrete_t) :: t1
class(base_t), allocatable :: t2

call write_msg (t1) ! prints "base type"
call t1%msg () ! prints "concrete type"

allocate (concrete_t :: t2)
call write_msg (t2) ! prints "base type"
! call t2%msg () ! rejected by the compiler (t2%msg
inaccessible)
select type (t2)
type is (concrete_t)
call t2%msg () ! prints "concrete type"
end select

end program main
-----------------------------------------------------------


So the output is:
base type
concrete type
base type
concrete type

-----------------------------------------------------------

I guess this makes sense. What does the standard say here?

-- Wolfgang


--
E-mail: firstnameini...@domain.de
Domain: yahoo

Wolfgang Kilian

unread,
Sep 27, 2012, 4:20:48 AM9/27/12
to
I get the output

ta

tb


when I compile this code and run it. So the there are two compilers
with different answers.

Ian Harvey

unread,
Sep 27, 2012, 7:30:23 AM9/27/12
to
...
> -----------------------------------------------------------
>
> I guess this makes sense. What does the standard say here?
>
> -- Wolfgang

(I think this is equivalent.)

I get concrete type four times with gfortran 4.8x from early August and
ifort 13.0.0.

My reading of the std was that the overriding happens - accessibility
not being mentioned as a criteria in 4.5.7.3 - the binding just has to
have the "same binding name as a type-bound procedure".

I was hoping this was the case, otherwise type bound operators become
clunky - the specific procedures that implement them in the type where
they are declared would otherwise need to be public, which exposes
implementation detail. I want to do:

TYPE, ABSTRACT, PUBLIC :: Parent
CONTAINS
PROCEDURE(parent_op), DEFERRED, PRIVATE :: op_binding
GENERIC :: OPERATOR(.Op.) => op_binding
END TYPE

! elsewhere...
TYPE, EXTENDS(Parent), PUBLIC :: Extension
CONTAINS
PROCEDURE, PRIVATE :: op_binding => extension_op
END TYPE

For CLASS(Parent) :: obj I don't want clients to be able to directly
reference "obj%op_binding", I want them to have to go via ".Op. obj".

Wolfgang Kilian

unread,
Sep 27, 2012, 8:51:26 AM9/27/12
to
On 09/27/2012 01:30 PM, Ian Harvey wrote:
> On 2012-09-27 6:05 PM, Wolfgang Kilian wrote:
>> On 09/27/2012 08:46 AM, Ian Harvey wrote:
>>> If I have a private binding in an extensible type that is in a
>>> particular module; I extend that type in another module and in that
>>> extended type I have a binding of the same name as the private binding
>>> in the parent type, does the binding in the extension type override the
>>> binding in the parent type?
>>
>> [...]
>
> My reading of the std was that the overriding happens - accessibility
> not being mentioned as a criteria in 4.5.7.3 - the binding just has to
> have the "same binding name as a type-bound procedure".

Maybe your interpretation is correct ... which would imply that the NAG
compiler has a bug.

Looking at F2008, there is also note 4.53 which says that inaccessible
bindings are also inherited. It doesn't say explicitly that they can be
overridden. And the last bullet in 4.5.7.3 prohibits private overriding
bindings if the overridden binding has the PUBLIC attribute - which one
can read as an indication that the overridden binding may also have the
PRIVATE attribute.

Any Standard expert can comment?


> I was hoping this was the case, otherwise type bound operators become
> clunky - the specific procedures that implement them in the type where
> they are declared would otherwise need to be public, which exposes
> implementation detail. I want to do:
>
> TYPE, ABSTRACT, PUBLIC :: Parent
> CONTAINS
> PROCEDURE(parent_op), DEFERRED, PRIVATE :: op_binding
> GENERIC :: OPERATOR(.Op.) => op_binding
> END TYPE
>
> ! elsewhere...
> TYPE, EXTENDS(Parent), PUBLIC :: Extension
> CONTAINS
> PROCEDURE, PRIVATE :: op_binding => extension_op
> END TYPE
>
> For CLASS(Parent) :: obj I don't want clients to be able to directly
> reference "obj%op_binding", I want them to have to go via ".Op. obj".

Same here. After the compiler didn't read it that way, I was forced to
make the overridden bindings public.

Wolfgang Kilian

unread,
Oct 1, 2012, 8:43:48 AM10/1/12
to
On 09/27/2012 01:30 PM, Ian Harvey wrote:
> On 2012-09-27 6:05 PM, Wolfgang Kilian wrote:
>> On 09/27/2012 08:46 AM, Ian Harvey wrote:
>>> If I have a private binding in an extensible type that is in a
>>> particular module; I extend that type in another module and in that
>>> extended type I have a binding of the same name as the private binding
>>> in the parent type, does the binding in the extension type override the
>>> binding in the parent type?
>> [...]

>> I guess this makes sense. What does the standard say here?
>>
>> -- Wolfgang
>
> (I think this is equivalent.)
>
> I get concrete type four times with gfortran 4.8x from early August and
> ifort 13.0.0.
>
> My reading of the std was that the overriding happens - accessibility
> not being mentioned as a criteria in 4.5.7.3 - the binding just has to
> have the "same binding name as a type-bound procedure".
>
> I was hoping this was the case, otherwise type bound operators become
> clunky - the specific procedures that implement them in the type where
> they are declared would otherwise need to be public, which exposes
> implementation detail. I want to do:
>
> TYPE, ABSTRACT, PUBLIC :: Parent
> CONTAINS
> PROCEDURE(parent_op), DEFERRED, PRIVATE :: op_binding
> GENERIC :: OPERATOR(.Op.) => op_binding
> END TYPE
>
> ! elsewhere...
> TYPE, EXTENDS(Parent), PUBLIC :: Extension
> CONTAINS
> PROCEDURE, PRIVATE :: op_binding => extension_op
> END TYPE
>
> For CLASS(Parent) :: obj I don't want clients to be able to directly
> reference "obj%op_binding", I want them to have to go via ".Op. obj".

I just got the response from NAG support that this issue was actually
discussed and resolved in the interpretation request F08/0052. The
answer is that the behavior of the NAG compiler is actually correct. In
my understanding: the private binding should be treated by other modules
as if it never existed. To enable overriding, it has to be made PUBLIC.

This implies that both gfortran and ifort should be modified. (Of
course, neither of them claims to implement the F2008 standard, yet.)

Tobias Burnus

unread,
Oct 1, 2012, 9:51:23 AM10/1/12
to
Wolfgang Kilian wrote:
> I just got the response from NAG support that this issue was actually
> discussed and resolved in the interpretation request F08/0052. The
> answer is that the behavior of the NAG compiler is actually correct. In
> my understanding: the private binding should be treated by other modules
> as if it never existed. To enable overriding, it has to be made PUBLIC.
>
> This implies that both gfortran and ifort should be modified. (Of
> course, neither of them claims to implement the F2008 standard, yet.)

That's a known issue tracked at
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47805 - Unfortunately, no
one had yet the time to fix this issue. The edits of the interpretation
request have been included in Fortran 2008's Corrigendum 1.

Tobias

Ian Harvey

unread,
Oct 1, 2012, 6:52:28 PM10/1/12
to
Thanks for asking them.

If that's what it is then that's what it is, but it's a shame - you
can't avoid implementation leaking through via bindings that now have to
be public. Seems like a bit of a hole in the language. An attribute
for a binding that says "you can override me, but not otherwise
reference me" would be handy (and probably not that hard to implement,
given at least three compilers accidentally do that already...).

Given 4.5.7.2 and note 4.53 - what's the point in elaborating around how
inaccessible bindings are still inherited? If accessibility is
absolute, whether they are or are not inherited makes absolutely no
difference.

Private bindings, as they've then been defined, don't strike me as being
particularly useful. The entire type hierarchy that may want to
override that binding now needs to be in the same module (and beyond
syntactic sugar - the concept of bindings pretty much exists to allow
for overriding). In the practical F2003 code that I've written (so
admittedly sans submodule support) I've nearly always had each extension
in its own module, which is quite the opposite extreme.

Oh well, time to go and append "reference_me_and_you_will_be_fired" to
all my quasi-private bindings.



Ian Harvey

unread,
Oct 1, 2012, 8:09:21 PM10/1/12
to
On 2012-10-02 8:52 AM, Ian Harvey wrote:
...
>
> Given 4.5.7.2 and note 4.53 - what's the point in elaborating around how
> inaccessible bindings are still inherited? If accessibility is
> absolute, whether they are or are not inherited makes absolutely no
> difference.

Ok, one difference - if a deferred private bindings is inherited then
extension outside of the module that defines the type with the deferred
private binding is impossible.

...
0 new messages