Consider the following types.
TYPE, ABSTRACT:: base
...
CONTAINS
SUBROUTINE sanity_check
END SUBROUTINE
END TYPE
TYPE, EXTENDS(base):: concrete1
...
END TYPE
TYPE, EXTENDS(base):: concrete2
...
END TYPE
where ...
indicate some data which is not relevant for the question. The types concrete1
and concrete2
have their constructors defined in the code, and the subroutine sanity_check
is also implemented.
Now, I would like to automatically execute sanity_check
at the end of the constructors of concrete1
and concrete2
. In other words, sanity_check
should be executed at the end of the constructors of any type that extends base
, without the need to call it explicitly in the constructors. This would be useful if other programmers were to write a type that extends base
, to check that all the data has been initialized properly by their extended type, without the need for the programmer to call sanity_check
explicitly.
Is this somehow possible? I have seen that it is possible to define an interface for an abstract type, but I don't know if that can be used to achieve what I describe above (or if it is of any use at all, since an abstract type cannot be instantiated by definition).
CodePudding user response:
As francescalus says, it's not possible to do exactly what you want.
However, if all of your constructors take the same arguments then you can get reasonably close to what you want by replacing your constructors with initialisation subroutines.
You can give the base
class an initialise
subroutine which initialises an object by first calling a deferred
helper
subroutine, and then calling sanity_check
.
The base
class would look something like:
module base_module
implicit none
type, abstract :: base
contains
procedure :: sanity_check
procedure :: initialise
procedure(helper_base), deferred :: helper
end type
contains
subroutine sanity_check(this)
class(base), intent(in) :: this
end subroutine
subroutine initialise(this, args)
class(base), intent(out) :: this
integer, intent(in) :: args
call this%helper(args)
call this%sanity_check
end subroutine
abstract interface
subroutine helper_base(this, args)
import base
class(base), intent(out) :: this
integer, intent(in) :: args
end subroutine
end interface
end module
Each child class would then overload helper
, and the initialise
subroutine would automatically call sanity_check
as desired.
A child class would look something like:
module concrete_module
implicit none
type, extends(base) :: concrete
contains
procedure :: helper => helper_concrete
end type
contains
subroutine helper_concrete(this, args)
class(concrete), intent(out) :: this
integer, intent(in) :: args
end subroutine
end module
You would then construct a concrete
object as e.g.
type(concrete) :: foo
integer :: args = 1
call foo%initialise(args)
If you wanted, you could re-introduce the foo = concrete(args)
syntax by writing a thin wrapper which calls initialise
, although this might be more work than just writing constructors manually.