On Thursday, August 22, 2019 at 5:36:53 PM UTC-4, Ian Harvey wrote:
> ..
> Call the procedure directly, using its name, rather than via a binding
> of a type. ..
Good quick workaround for OP.
There is a reason why I did not suggest such a fix which is a commercial context and/or a complex team situation with multiple priorities/personalities with tendencies to stomp on each others' 'data' either intentionally or otherwise. One can have several of the 'showInfo' type of procedures toward initialization, setter/getter, IO or post-processing, etc. that operate on 'data' encapsulated in an abstract 'class'. One can then end up needing to "expose" them all, meaning one has to effectively move away from the starting premise of an OO approach which is to consider *information hiding* as much as possible. In Fortran parlance that would typically mean paying close attention to what is PUBLIC in a module with the default visibility being made PRIVATE. This will typically accompany the practice where the abstract 'class' is in one module and a concrete extension is in another. Thus a variant of an example in the original post can mean the procedure be public which can be discomforting depending on what it does. See below - try linking it:
module shape_m
private !<--
type, abstract, public :: shape_t
private !<--
real :: x, y
contains
!private !<-- desired generally with only a few bindings made public
procedure :: initShape
procedure :: showInfo
procedure(calculateSurfaceProto), deferred :: calculateSurface
generic :: Init => initShape
end type
abstract interface
subroutine calculateSurfaceProto(self, s)
import shape_t
class(shape_t), intent(in) :: self
real, intent(inout) :: s
end subroutine calculateSurfaceProto
end interface
!public :: showInfo !<-- Under "information hiding" considerations, one is in a bind
contains
subroutine showInfo(self)
class(shape_t), intent(in) :: self
print*, "x = ", self%x, "y = ", self%y
end subroutine
subroutine initShape(self, x, y)
class(shape_t), intent(inout) :: self
real, intent(in) :: x
real, intent(in) :: y
self%x = x
self%y = y
end subroutine
end module
module square_m
use shape_m !<-- preferred is ONLY clause with only the 'class' use-associated
private
type, extends(shape_t), public :: square_t
private !<--
real :: size
contains
!private !<-- private is preferred
procedure :: initSquare
procedure :: showInfo => showSquareInfo
procedure :: calculateSurface => calculateSquareSurface
generic :: Init => initSquare
end type
contains
subroutine showSquareInfo(self)
class(square_t), intent(in) :: self
real :: surf
call showInfo(self)
call self%calculateSurface(surf)
print *, "Surface = ", surf
end subroutine
subroutine calculateSquareSurface(self,s)
class(square_t), intent(in) :: self
real, intent(inout) :: s
s = self%size * self%size
end subroutine
subroutine initSquare(self, x, y, size)
class(square_t), intent(inout) :: self
real, intent(in) :: x
real, intent(in) :: y
real, intent(in) :: size
call self%Init(x, y)
self%size = size
end subroutine
end module
program expl
use square_m, only : square_t
implicit none
type(square_t) ::sq
call sq%Init( x=1.0, y=2.0, size=5.0 )