Reputation: 1470
I have a base module that defines some subroutines (sub1
, sub2
, sub3
). Then, I want to override these subroutines in a series of child modules.
I know how to do that with separate modules and deferred types, but I decided to give it a try with submodules. Unfortunately, I don't understand the usage of them.
This is what I have so far:
BaseModule:
module BaseModule
implicit none
interface
subroutine sub1(idx)
implicit none
integer, intent(in) :: idx
end subroutine sub1
subroutine sub2(idx)
implicit none
integer, intent(in) :: idx
end subroutine sub2
subroutine sub3(idx)
implicit none
integer, intent(in) :: idx
end subroutine sub3
end interface
end module BaseModule
ChildModule1:
submodule (BaseModule) ChildModule1
implicit none
type :: Child1
contains
module procedure :: sub1
module procedure :: sub2
end type
contains
module subroutine sub1
print*, "Child 1 - execute 'sub1' - idx = ", idx
end subroutine sub1
module subroutine sub2
print*, "Child 1 - execute 'sub2' - idx = ", idx
end subroutine sub2
end submodule ChildModule1
ChildModule2:
submodule (BaseModule) ChildModule2
implicit none
type :: Child2
contains
module procedure :: sub1
module procedure :: sub2
module procedure :: sub3
end type
contains
module subroutine sub1
print*, "Child 2 - execute 'sub1' - idx = ", idx
end subroutine sub1
module subroutine sub2
print*, "Child 2 - execute 'sub2' - idx = ", idx
end subroutine sub2
module subroutine sub3
print*, "Child 2 - execute 'sub3' - idx = ", idx
end subroutine sub3
end submodule ChildModule2
test:
program test
use ChildModule1
use Childmodule2
implicit none
integer :: idx
type(Child1) :: c1
type(Child2) :: c2
do idx = 1, 10
!! Child1 outputs
call c1%sub1(idx)
call c1%sub2(idx)
!! Child2 outputs
call c1%sub1(idx)
call c2%sub2(idx)
call c1%sub3(idx)
end do
end program test
The idea I get of submodules is that I don't have to declare all the inouts again, but what if I want to use the same subroutine (e.g. sub1
) within more submodules where I declare different types? Right now I get the compile error:
Error: MODULE PROCEDURE at (1) must be in a generic module interface
Upvotes: 2
Views: 1913
Reputation: 1470
In order to sum it all up I have decided to give a working example from what I was trying to do. Thanks again to @Rodrigo Rodrigues for clarifying what submodules really are. I'm not sure if this approach is the right way of doing but it works for me.
The Task
sub
which is defined in a Base Classsub
gets overridden according to the needsThe Base Module
module BaseClass
implicit none
type, abstract :: Base ! <-- the base class with subroutine "sub"
contains
procedure(sub_interface), nopass, deferred :: sub
end type
interface
subroutine sub_interface(i) ! <-- the interface is defined here
implicit none
integer, intent(in) :: i
end subroutine sub_interface
end interface
end module BaseClass
The Child Module
module ChildClass
implicit none
type, extends(Base) :: Child ! <-- we extend the Base Class
contains
procedure, nopass :: sub
end type
interface
module subroutine sub(i) ! <-- the interface for the submodule (unfortunately we have to declare the entire thing again)
implicit none
integer, intent(in) :: i
end subroutine sub
end interface
end module ChildClass
The Sub Module
submodule (ChildClass) ChildSub
contains
module procedure sub ! <-- we finally get to define the subroutine
print*, "The answer is :", i
end procedure
end submodule
The Program
program test
use ChildClass
implicit none
type(Child) :: c
integer :: i
do i=1, 10
call c%sub(i)
end do
end program test
We now could have multiple Child Classes which all extend the Base Class and call sub
accordingly. What I personally don't like so much is that we have to declare sub
twice, once in the iterface of the base class and then again in the interface of the child class in order to use a submodule. This is code repitition but maybe this could be done better.
Upvotes: 3
Reputation: 8546
I will try to clear some misconceptions I think you have about the submodules mechanism in Fortran.
Then, I want to override these subroutines in a series of child modules.
You don't override procedures with submodules, you implement them.
The idea I get of submodules is that I don't have to declare all the inouts again,
If by inouts you mean procedure's declarations and signatures (interfaces), then yes, you don't need to (but could) repeat them in submodules, but no, this is not the purpose of submodules.
but what if I want to use the same subroutine (e.g.
sub1
) within more submodules where I declare different types?
Well, maybe I have to briefly explain what submodules are and what they are not. For more details, please refer to this good article written by @SteveLionel, or to this entry on Fortran wiki, or your compiler's reference (whatever it is), or even to your favorite book on Modern Fortran.
As I said in another question, submodules are a feature added to the language to address one specific question: separation of interface and implementation. The main motivation was the compile cascades generated when you needed to change just a implementation detail in a module.
A submodule has access to entities on the parent module by host association, but the parent module doesn't know about the existence of this submodules. When you declare the type Child1
inside submodule ChildModule1
, it is only accessible inside this submodule itself, but not in the parent module BaseModule
.
Furthermore, ChildModule1
is not a module, and cannot be use
d, like you are tying to do, in the main program or any other program unit. The only role of a submodules is to implement module procedures
that are missing implementation in its parent module.
Summing up: lay out your source files and program units in a modularized, sensible fashion, and use submodules if it makes sense to have the implementations of your procedures independent of their declarations (something akin c
header and source files... but take this comparison with a grain of salt).
Edit:
It occurs me that you may be thinking module
and submodule
in Fortran are related to classes and subclasses in other languages. They don't! Maybe this is a common misconception, I don't know.
Fortran has user-defined types. They can bind methods, constructors and destructors, they can encapsulate data, they can be extended, they can be dynamically dispatched, they can be declared abstract, they can defer and override members. This is equivalent to classes in other languages. You can (and it is good practice) separate each type and related stuff into its correspondent modules. Likewise, you can have a module for each extend type, if you want.
But, again, submodules have nothing to do with this.
Upvotes: 7