Reputation: 458
I am looking for a way to access private components of a Fortran class (derived type in Fortran's terminology) from a descendant class. For example, suppose class A has a component x, which is declared as private. Now consider a second class, B, which inherits from the base class A. In that case, class B has no direct access to x, so any try to access B%x is not allowed. The two solutions I can think of are:
(1) Declare x as public. This, however, will make x globally accessible, which abuses data hiding and thus it is rejected as an acceptable solution to the problem.
(2) Implement procedures for getting/setting A%x, such as A%getX() and A%setX(). This is not only cumbersome, but will also allow (indirect) access to A%x everywhere in the program - not only in child classes.
What I want is a way to access A%x from A's child classes, but otherwise x should be inaccessible elsewhere. C++ has the "protected" attribute for that purpose, but as far I know, the "protected" attribute in Fortran 2003 has a different meaning (it makes A%x accessible everywhere and only protects its value, which cannot be changed outside the class).
Upvotes: 12
Views: 2942
Reputation: 458
Implementing everything in a single module, as Mark suggested, bypasses the problem but leads to very long modules for "real world" programs, which is not convenient.
Submodules is the answer to my question, as IanH suggested. Unfortunately, submodules is a Fortran 2008 feature not implemented yet in gfortran (and probably most compilers out there). As a temporary workaround, I ended up using a single module defining all the types, and methods related to those types are defined in separate files, which are then included to the main module using the "include" command. This is essentially Mark's solution, just avoids huge files. It works as a workaround, however.
Upvotes: 0
Reputation: 21431
The language doesn't have that capability in the general sense (beyond the do everything in the one module approach that High Performance Mark suggests), and you are not alone in wanting this.
As you note in the comments to Mark's answer, accessibility is based around modules, not types.
Note though, that use of submodules would perhaps partly solve your problem. You use the one big module approach suggested by HIgh Performance Mark, but that module can be split up amongst multiple program units. Procedures that implement the bindings for a type could be provided together in a submodule as separate module procedures, the module itself then only holds the type definitions and separate interface bodies. Because submodules are conceptually part of their ancestor module, any components and types in the module that are private in the module are still accessible.
One conceptual difference between Fortran and other languages such as C++ (say) is that the procedures that actually do things are not "part" of a type - instead types have bindings that refer to a procedure. Bindings from multiple types can refer back to the one procedure. Consequently, while inside a type definition it is clear whether you are working in a scope that is an extension of the parent type, outside the type definition it is less clear. A language facility that implements this feature would need to accommodate that difference in some way.
Upvotes: 10
Reputation: 78316
This is probably an extended comment rather than an answer ...
I don't really understand your question, or perhaps what I don't understand is what you are trying to do. I agree with you that your choice (1) is unappealing, we want private
components to be private.
But when I come to your point (2) I can write a module like this:
module types
type :: supertype
integer, private :: c1 = 1
end type supertype
type, extends(supertype) :: subtype
integer :: c2
contains
procedure, pass :: getc1
end type subtype
contains
integer function getc1(this)
class(subtype), intent(inout) :: this
this%c1 = 12 ! Just to show that the sub-type can set super-type components
getc1 = this%c1 ! Return the latest value of c1
end function getc1
end module types
This compiles without an error (Intel Fortran 13.something). This does leave the type-bound procedure getc1
available to all users of the module. However, if I change the procedure declaration from
procedure, pass :: getc1
to
procedure, pass, private :: getc1
the procedure is no longer use-able outside the module. This looks to me like a sub-type having access to the super-type's private components without that access leaking to the outside world.
This code is standard-conforming as both I and my compiler understand the standard.
Upvotes: 5