TrippLamb
TrippLamb

Reputation: 1619

Breaking up a Module into Multiple Files in Fortran

I'm attempting to add conversion functions to between different derived types. I'm wanting them to be functions of the first derived type that returns the other derived type. This is no problem as long as they are in the same file and module. But I'd really like them to be able to be separated into multiple files since otherwise it would be a very large file. I can't figure out how to do this because of dependencies, and the lack of namespace in Fortran.

Is there a way to do this?

Here is an example of what I'd like to be dividing into two files (one for each derived type).

Module ConversionStuff
  implicit none

  type A_T
    real :: a, b, c
  contains
    procedure :: toX => a_toX
  end type A_T

  type X_T
    real :: x, y, z
  contains
    procedure :: toA => x_toA
  end type X_T

  contains

  function a_toX(this) result(x)

     class(A_T), intent(inout) :: this
     type(X_T) :: x

     x%x = this%a * 2
     x%y = this%b * 2
     x%z = this%c * 2

  end function a_toX

  function x_toA(this) result(a)

     class(X_T), intent(inout) :: this
     type(A_T) :: a

     a%a = this%x * 0.5
     a%b = this%y * 0.5
     a%c = this%z * 0.5

  end function x_toA

End Module ConversionStuff

I do apologize if there is a typo. I don't have an easy way to compile Fortran on this computer.

Upvotes: 3

Views: 1197

Answers (2)

TrippLamb
TrippLamb

Reputation: 1619

After working on other things and coming back to this almost 2 months later. I found something I think is far more simple and elegant for this specific usage. I'm going to leave the previously accepted answer because it definitely answers the question, but this is an alternative method.

It uses the include keyword. I didn't understand until now that it doesn't compile included file until it is compiling the including file. Maybe there is something I don't understand, but for this situation where I only want to split into multiple files so that my single file isn't enormous, I think this method is worth the trade off in what I lose for it not being a module. If there is something I'm missing please let me know.

My solution is below.

Module ConversionStuff
  implicit none

  type A_T
    real :: a, b, c
  contains
    procedure :: toX => a_toX
  end type A_T

  type X_T
    real :: x, y, z
  contains
    procedure :: toA => x_toA
  end type X_T

  contains

  include "A.f90"
  include "X.f90"

End Module ConversionStuff

A.f90

function a_toX(this) result(x)

    class(A_T), intent(inout) :: this
    type(X_T) :: x

    x%x = this%a * 2
    x%y = this%b * 2
    x%z = this%c * 2

end function a_toX

X.f90

function x_toA(this) result(a)

    class(X_T), intent(inout) :: this
    type(A_T) :: a

    a%a = this%x * 0.5
    a%b = this%y * 0.5
    a%c = this%z * 0.5

 end function x_toA

Upvotes: 0

IanH
IanH

Reputation: 21431

Within the current language this is easily enough dealt with through submodules - both type definitions go into the ancestor module along with the interfaces for the "shared" separate module procedures, procedure definitions are then split between submodules as it suits.

MODULE ConversionStuff
  IMPLICIT NONE
  TYPE :: A_T
    REAL :: a, b, c
  CONTAINS
    PROCEDURE :: toX => a_toX
  END TYPE A_T
  TYPE :: X_T
    REAL :: x, y, z
  CONTAINS
    PROCEDURE :: toA => x_toA
  END TYPE x, y, z
  INTERFACE
    MODULE FUNCTION a_toX(this) RESULT(x)
      IMPLICIT NONE
      CLASS(A_T), INTENT(IN) :: this
      TYPE(X_T) :: x
    END FUNCTION a_toX
    MODULE FUNCTION x_toA(this) RESULT(a)
      IMPLICIT NONE
      CLASS(X_T), INTENT(IN) :: this
      TYPE(A_T) :: a
    END FUNCTION x_toA
  END INTERFACE
END MODULE ConversionStuff

SUBMODULE (ConversionStuff) Procedures_for_X
  IMPLICIT NONE
CONTAINS
  MODULE PROCEDURE a_toX
    x%x = this%a * 2
    x%y = this%b * 2
    x%z = this%c * 2
  END PROCEDURE a_toX
END SUBMODULE Procedures_for_X
...

Prior to Fortran 2008, you can sometimes use an alternative approach that emulates the above - the implementation of the procedures goes in a separately compiled set of external procedures that use the module. Care needs to be taken that the external procedures do not have visibility of their own interface.

MODULE ConversionStuff
  IMPLICIT NONE
  TYPE :: A_T
    REAL :: a, b, c
  CONTAINS
    PROCEDURE :: toX => a_toX
  END TYPE A_T
  TYPE :: X_T
    REAL :: x, y, z
  CONTAINS
    PROCEDURE :: toA => x_toA
  END TYPE x, y, z
  INTERFACE
    FUNCTION a_toX(this) RESULT(x)
      IMPORT :: A_T
      IMPORT :: X_T
      IMPLICIT NONE
      CLASS(A_T), INTENT(IN) :: this
      TYPE(X_T) :: x
    END FUNCTION a_toX
    FUNCTION x_toA(this) RESULT(a)
      IMPORT :: A_T
      IMPORT :: X_T
      IMPLICIT NONE
      CLASS(X_T), INTENT(IN) :: this
      TYPE(A_T) :: a
    END FUNCTION x_toA
  END INTERFACE
  PRIVATE :: a_toX
  PRIVATE :: x_toA
END MODULE ConversionStuff

FUNCTION A_toX(this) RESULT(x)
  USE ConversionStuff
  IMPLICIT NONE
  CLASS(A_T), INTENT(IN) :: this
  TYPE(X_T) :: x
  ...etc...
END FUNCTION A_toX

There are limitations for the use of Fortran's accessibility attributes (PUBLIC and PRIVATE) for this second approach.

Note that the problem has nothing to do with namespaces, as the concept is typically defined.

Upvotes: 2

Related Questions