Emulating namespaces in Fortran 90
Asked Answered
I

4

14

One of the most troublesome issues with Fortran 90 is the lack of namespacing. In this previous question "How do you use Fortran 90 module data" from Pete, it has been discussed the main issue of USE behaving like a "from module import *" in Python: everything that is declared public in the module is imported as-is within the scope of the importing module. No prefixing. This makes very, very hard to understand, while reading some code, where a given identifier comes from, and if a given module is still used or not.

A possible solution, discussed in the question I linked above, is to use the ONLY keyword to both limit the imported identifiers and document where they come from, although this is very, very tedious when the module is very large. Keeping the module small, and always using USE : ONLY is a potentially good strategy to work around the lack of namespacing and qualifying prefixes in Fortran 9X.

Are there other (not necessarily better) workaround strategies? Does the Fortran 2k3 standard say anything regarding namespacing support?

Ionian answered 6/10, 2010 at 16:10 Comment(1)
A late comment, it seems Fortran 03 can use % in OOP fortranwiki.org/fortran/show/Object-oriented+programming, somehow resembles namespace ::Stupa
B
6

For me this is the most irritating Fortran feature related to modules. The only solution is to add common prefix to procedures, variables, constants, etc. to avoid namespace collisions.

One can prefix all entities (all public entities seems to be more appropriate) right inside the module:

module constants

  implicit none

  real, parameter :: constants_pi = 3.14
  real, parameter :: constants_e = 2.71828183

end module constants

Drawback is increased code verbosity inside the module. As an alternative one can use namespace-prefix wrapper module as suggested here, for example.

module constants_internal

  implicit none

  real, parameter :: pi = 3.14
  real, parameter :: e = 2.71828183

end module constants_internal

module constants

  use constants_internal, only: &
    constants_pi => pi, &
    constants_e => e

end module constants

The last is a small modification of what you, Stefano, suggested.

Even if we accept the situation with verbosity the fact that Fortran is not case-sensitive language force us to use the same separator (_) in entities names. And it will be really difficult to distinguish module name (as a prefix) from entity name until we do not use strong naming discipline, for example, module names are one word only.

Bureau answered 6/10, 2010 at 18:22 Comment(3)
if your second paragraph, if I understand correctly, you mean that e.g. physics_const_earth_radius does not tell whether physics is the module name or physics_const. You could use double underscores: physical_constants__earth_radiusConjoint
@Matthias009 sure, you can. But I would rather prefer something like _mod_ instead for visual clarity.Bureau
How would this work if there are more than 255 entities in the module (255 being the maximum number of continuation lines in F2003)? Can one split the use statement in several ones?Copyholder
R
6

Having several years of Fortran-only programming experience (I got into Python only a year ago), I was not aware of such concept as namespaces for a while. So I guess I learned to just keep track of everything imported, and as High Performance Mark said, use ONLY as much as you have time to do it (tedious).

Another way I can think of to emulate a namespace would be to declare everything within a module as a derived type component. Fortran won't let you name the module the same way as the namespace, but prefixing module_ to module name could be intuitive enough:

MODULE module_constants
IMPLICIT NONE

TYPE constants_namespace
  REAL :: pi=3.14159
  REAL ::  e=2.71828
ENDTYPE

TYPE(constants_namespace) :: constants

ENDMODULE module_constants


PROGRAM namespaces
USE module_constants
IMPLICIT NONE

WRITE(*,*)constants%pi
WRITE(*,*)constants%e

ENDPROGRAM namespaces
Rubino answered 22/11, 2011 at 16:0 Comment(3)
Note: this works for vars but not for functions. The fact that fortran90 does not support subroutine pointers is shocking, to say the least. With just this small feature, it would unlock a huge amount of possibilities.Ionian
Right. For subroutines you still have to stick with USE..ONLY, with optional renaming, as suggested by kemiisto. I guess this is something that should be considered for next Fortran standard release.Rubino
In Fortran 2003 (admittedly not in Fortran 90), the type-bound procedure concept can be used to prefix the type-name in front of functions and subroutines as done above for variables. But I don't know if this affects the performance.Decern
D
3

Fortran 2003 has the new ASSOCIATE construct and don't forget the possibility of renaming USE- associated entities. But I don't think that either of these is much closer to providing a good emulation of namespaces than Fortran 90 already has, just (slightly) better workarounds.

Like some of the respondents to the question you link to, I tend to think that modules with very many identifiers should probably be split into smaller modules (or, wait for Fortran 2008 and use submodules) and these days I almost always specify an ONLY clause (with renames) for USE statements.

I can't say that I miss namespaces much, but then I've never had them really.

Dylandylana answered 6/10, 2010 at 16:31 Comment(0)
C
1

No one else summited this suggestion as an answer (though someone did in the comments of one answer). So I'm going to submit this in hopes it may help someone else.

You can emulate namespaces in the following way, and I would hope there would be no noticeable performance hit for doing so from the compiler (if so all object oriented Fortran programming is sufferings). I use this pattern in my production code. The only real downfall to me is the lack of derived type contained parameter variables, but I offer an option for that as well below.

Module Math_M

    IMPLICIT NONE
    
    PRIVATE

    public :: Math

    Type Math_T
        real :: pi=3.14159
    contains
        procedure, nopass :: e => math_e
        procedure :: calcAreaOfCircle => math_calcAreaOfCircle
    End Type

    Type(Math_T) :: Math
    real, parameter :: m_e = 2.71828

    contains

    function math_e() result(e)
        real :: e
        e = m_e
    end function math_e

    function math_calcAreaOfCircle(this, r) result(a)

        class(Math_T), intent(in) :: this
        real, intent(in) :: r

        real :: a

        a = this%pi * r**2.0
    end function math_calcAreaOfCircle
End Module Math_M

And the usage

Program Main

    use Math_M

    IMPLICIT NONE

    print *, Math%pi
    print *, Math%e()
    print *, Math%calcAreaOfCircle(2.0)


End Program Main

Personally I prefer using $ over the _ for module variables, but not all compilers like that without compiler flags. Hopefully this helps someone in the future.

Calendra answered 7/4, 2022 at 18:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.