the code below compiles with ifort 17.01 and gfortran 6.3, but not with ifort 17.02. The error message is:
"A private component name is accessible only within the module containing the type definition.
Module Mod_Parent Type, Abstract :: parent Integer, private :: a contains Procedure(SubSetA), Pass, deferred :: SetA End type parent Abstract Interface Subroutine SubSetA(this) Import parent Class(parent), Intent(InOut) :: this end subroutine end Interface Private :: SubSetA End Module Mod_Parent Module Mod_Child use Mod_Parent Type, extends(parent) :: Child contains Procedure, Pass :: SetA => SubSetA End type Child Interface Module Subroutine SubSetA(this) Class(child), Intent(InOut) :: this end subroutine end Interface Private :: SubSetA End Module Mod_Child Submodule(Mod_Child) Set Contains Module Procedure SubSetA this%a=1 End Procedure End Submodule Set Program Test use Mod_Child Type(Child) :: x call x%setA() End Program Test
Is the code not standard compliant or is it a compiler bug. I thought the "inheritance vs private" clash was resolved with the advent of submodules.
The error occurs as a result of 17.0.2 containing a fix for the earlier reported error here. I believe 17.0.2 has it correct now. The submodule Set is tries accessing "a" via module Mod_Child and USE association with Mod_Parent which is not allowed. Variable "a" would be accessible within a submodule of Mod_Parent.
I don't know whether this discussion here helps with your "inheritance vs. private" clash question.
I reported a bug here https://software.intel.com/en-us/forums/intel-fortran-compiler-for-linux-and-mac-os-x/topic/704535. But there is a notable difference in the structure of the program. The example above is about inheritance, the one in the bug report not.
Your link is of no help because that fellow wanted to declare local variables private which has nothing to do with inheritance.
What I understand from reading this http://fortranwiki.org/fortran/show/Submodules, especially "....Entities in a submodule have access to the all entities and components of their ancestor module and any ancestor submodules by host association, just as if they were physically present inside the source code of their ancestors. .....", makes me concluding that the bug fix in 17.02 produced a bug. This may be also be obvious due to the error message saying implicitly that the "private" statement becomes absolutely useless as soon as the slightest inheritance is involved (that is the clash between inheritance and private components which was meant to be solved with submodules). However, someone else more into the language of the 2008 standard documentation may back or dismiss my view.
The compiler is correct.
The private component `a` is declared in the Mod_Parent module. Only stuff inside the Mod_Parent module, or its submodule descendants, can access that component.
The submodule extends Mod_Child. Mod_Child is not Mod_Parent. Mod_Child and its submodules have no business accessing private stuff of Mod_Parent.
Inheritance - in the sense of type extension - doesn't change things.
Thanks Ian for this clarification. Since you are a "black belt" it doesn't seem to make sense do start to dig around in the standard trying to proof you wrong. However this all is very sobering. Let me just reiterate what you have said in a different way to check whether I got you right: As soon as one moves slightly into the oop world with inheritance, the "private" statement will be the most redundant language feature. That is because one would constantly have to alter parent class code (having private components) as soon as new child classes are implemented. Am I right??
If so, any savety measures in terms of limited access to class components are impossible to implement as soon as inheritance is involved. Is that right??
That would also mean that component hiding in a structure as in my example, where an abstract class has all components already, but private, and child classes just implement the methods is impossible. Is that right??
Thanks for clarification.
A possible work around might be this:
Module Mod_Types Type, Abstract :: parent Integer, private :: a contains Procedure(SubIF1), Pass, deferred :: SetA End type parent Type, extends(parent) :: Child contains Procedure, Pass :: SetA => SubSetA End type Child Abstract Interface Subroutine SubIF1(this) Import parent Class(parent), Intent(InOut) :: this end subroutine end Interface Interface Module Subroutine SubSetA(this) Class(child), Intent(InOut) :: this end subroutine end Interface Private :: SubSetA End Module Mod_Types Submodule(Mod_Types) Set Contains Module Procedure SubSetA this%a=1 write(*,*) this%a End Procedure End Submodule Set Program Test use Mod_Types Type(Child) :: x call x%setA() End Program Test
However, from my understanding that has the following implications:
In reference to the three questions - no.
Accessibility is based on modules, not on types. If you want the procedure
`SubSetA` original code to be able to access the private `a` component then SubSetA, or some appropriate portion of it, needs to be within Mod_Parent or its descendants.
That might be inconsistent with (I'm guessing...) an implied programming style of having a type definition per module, but in that case it is the programming style that needs to be revised.
Consider that types do not "own" procedures in Fortran. Instead, types may have bindings that reference procedures. The procedures stand on their own, with their own identity. It is quite possible (and useful, in some contexts) for one procedure to be bound to multiple types, procedures that are bound to a type do not have to be defined in the same module as the type (or any module, for that matter). When compiling the body of `SubSetA` in the original code, there is nothing to tell the compiler that there is some sort of special relation between `SubSetA` and the `parent` type, or the Mod_Parent module that holds the `parent` type definition.
Perhaps you are looking for something akin to protected accessibility in C++, where member functions of derived types (note that language has the possibility of a different ownership model for procedures and types) can access protected members of their base types. Fortran does not have an equivalent to protected accessibility of components.
With regard to the "no" and the second and third paragraph of your answer you basically trying to explain what I have implemented in the example(work around) above??
You could also keep the type definition in a separate module, and simply expose a procedure from the `Mod_Parent` module that permitted the operation on the a component of a polymorphic object of type `parent`. It is just the operation on the private `a` component that needs to be within the effective scope of the `Mod_Parent` module.
The name of the extension type (and the interfaces of all its bindings) only needs to be defined in the specification part of the module if that name needs to be accessible outside of the module. I don't know your requirements, but if the name of the extension type does not need to be accessible outside of the module, then you can pretty much just shove everything associated with the extension type into a submodule, bar a factory procedure of some sort.
Module Mod_Types Implicit WhateverIveMissed Private ! Clients of Mod_Types work with this type. Type, Abstract, Public :: parent Integer, private :: a contains Procedure(parent_SetA), Pass, Deferred :: SetA End type parent Abstract Interface Subroutine parent_SetA(this) Import parent Implicit None Class(parent), Intent(InOut) :: this end subroutine parent_SetA end Interface Interface Module Function MakeChild() Import parent Implicit None Class(parent), Allocatable :: MakeChild End Function MakeChild end Interface ! Clients of Mod_Types can also create specific varieties ! of Parent with factory procedures like... Public :: MakeChild End Module Mod_Types Submodule (Mod_Types) Submod_for_child Implicit None Type, Extends(parent) :: child contains Procedure :: SetA End type child Contains Module Function MakeChild() Class(parent), Allocatable :: MakeChild Type(child), Allocatable :: tmp Allocate(tmp) ! Construct tmp appropriately... Call Move_Alloc(tmp, MakeChild) End Function MakeChild Subroutine SetA(this) Class(child), Intent(InOut) :: this this%a=1 write(*,*) this%a End Subroutine SetA End Submodule Submod_for_child Program Test Use Mod_Types Implicit None Class(parent), Allocatable :: x ! Requires F2008 support, not currently in ifort :( ! x = MakeChild() Allocate(x, SOURCE=MakeChild()) Call x%setA() End Program Test
(Head compiled, I don't have access to a Fortran compiler at the moment.)
There has been discussion here and on c.l.f in the last few years about limitations in the current language that interfere with some typical OOP patterns, whether your use case is also affected by these limitations depends on specifics.
Thanks a lot.
Although the code may work it looks a bit like case interpretation in a legal battle (1+1-1+1-4+5=1+2). However, in my application childs need to be visible to the outside, and childs must be able to have more components than the parent, the inherited and their own. Then move_alloc wouldn't work. Thus I assume that my second example from above is the only way to implement oop.
(The use of MOVE_ALLOC is just a relatively efficient (source succinctness, perhaps performance) method of construction. You can construct the object in whatever way you consider appropriate. MOVE_ALLOC doesn't care about the number of components in each object - it just requires appropriate type compatibility between the FROM and TO arguments.)
What "OOP" is, or is not, is spectacularly subjective, but I don't consider #6 the only way. You need to make the appropriate design choices given the tools that the language gives you and your requirements. At the end of the day, the language's rules around accessibility are just aids provided by the language to authors of source code to help them write code that is consistent with their design.
To be clear about the first sentence of #9...
Module Mod_Parent Implicit None Private Type, Abstract, Public :: parent Integer, Private :: a Contains Procedure(parent_SetA), Deferred :: SetA End Type parent Abstract Interface Subroutine parent_SetA(this) Import parent Class(parent), Intent(InOut) :: this End Subroutine parent_SetA End Interface ! By making this procedure public, a fundamental ! characteristic of objects that are of any type that ! extends `parent` is that you can call `DoSetA` on ! that object. It is as fundamental to the ! characteristics of extensions of `parent` ! as any public component or binding. If extensions ! should not have such a capability, then perhaps they ! shouldn't be extensions - the typical OOP consideration ! of inheritance (i.e Liskov's substitution principle - ! "an extension object is a parent object") versus ! composition. Public :: DoSetA Contains Subroutine DoSetA(arg) Class(parent), Intent(InOut) :: arg ! Presumed complexity elided. arg%a = ... End Subroutine DoSetA End Module Mod_Parent Module Mod_Child Use Mod_Parent Implicit None Private Type, Extends(parent), Public :: child Contains Procedure :: SetA => child_SetA End Type child Contains Subroutine child_SetA(this) Class(child), Intent(InOut) :: this Call DoSetA(this) End Subroutine child_SetA End Module Mod_Child Program Test Use Mod_Child Type(Child) :: x Call x%SetA() ! As alluded to above, a possible issue is that there is nothing ! to stop client code then doing "direct" operations via DoSetA. ! Is this a problem? That depends... but Fortran's accessibility ! is solely based on modules, so whatever design is chosen needs ! to accommodate that. Call DoSetA(x) ! Maybe bad, maybe we don't care. End Program Test
.. That would also mean that component hiding in a structure as in my example, where an abstract class has all components already, but private, and child classes just implement the methods is impossible. Is that right?? ..
If your use case is indeed that "an abstract class has .. components already, but private, and child classes .. implement the methods", then you have to resort to something along the design suggested by IanH in message #10 where you implement "setter" procedures which are preferably not type-bound in order to maintain some "information hiding" from the callers who will most likely be 'use'ing the child modules and the extended types therein.
..Program Test Use Mod_Child .. ! As alluded to above, a possible issue is that there is nothing ! to stop client code then doing "direct" operations via DoSetA. ! .. End Program Test
As shown, DoSetA from parent class is not accessible to the client. So there exists a packaging option with modules for clients to prevent access to setters in the module containing the abstract types.