Flo Ragossnig
Flo Ragossnig

Reputation: 1470

How to use types in submodules Fortran

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

Answers (2)

Flo Ragossnig
Flo Ragossnig

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

  • define a type with a subroutine sub which is defined in a Base Class
  • define several child-types where sub gets overridden according to the needs

The 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

Rodrigo Rodrigues
Rodrigo Rodrigues

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 used, 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

Related Questions