Reputation: 1619
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
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
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