Pap
Pap

Reputation: 458

Protected inheritance in Fortran 2003/2008

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

Answers (3)

Pap
Pap

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

IanH
IanH

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

High Performance Mark
High Performance Mark

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

Related Questions