How do you USE Fortran 90 module data
Asked Answered
G

7

42

Let's say you have a Fortran 90 module containing lots of variables, functions and subroutines. In your USE statement, which convention do you follow:

  1. explicitly declare which variables/functions/subroutines you're using with the , only : syntax, such as USE [module_name], only : variable1, variable2, ...?
  2. Insert a blanket USE [module_name]?

On the one hand, the only clause makes the code a bit more verbose. However, it forces you to repeat yourself in the code and if your module contains lots of variables/functions/subroutines, things begin to look unruly.

Here's an example:

module constants
  implicit none
  real, parameter :: PI=3.14
  real, parameter :: E=2.71828183
  integer, parameter :: answer=42
  real, parameter :: earthRadiusMeters=6.38e6
end module constants

program test
! Option #1:  blanket "use constants"
!  use constants
! Option #2:  Specify EACH variable you wish to use.
  use constants, only : PI,E,answer,earthRadiusMeters
  implicit none

  write(6,*) "Hello world.  Here are some constants:"
  write(6,*) PI, &
       E, &
       answer, &
       earthRadiusInMeters
end program test

Update Hopefully someone says something like "Fortran? Just recode it in C#!" so I can down vote you.


Update

I like Tim Whitcomb's answer, which compares Fortran's USE modulename with Python's from modulename import *. A topic which has been on Stack Overflow before:

  • ‘import module’ or ‘from module import’

    • In an answer, Mark Roddy mentioned:

      don't use 'from module import *'. For any reasonable large set of code, if you 'import *' your will likely be cementing it into the module, unable to be removed. This is because it is difficult to determine what items used in the code are coming from 'module', making it east to get to the point where you think you don't use the import anymore but its extremely difficult to be sure.

  • What are good rules of thumb for python imports?

    • dbr's answer contains

      don't do from x import * - it makes your code very hard to understand, as you cannot easily see where a method came from (from x import *; from y import *; my_func() - where is my_func defined?)

So, I'm leaning towards a consensus of explicitly stating all the items I'm using in a module via

USE modulename, only : var1, var2, ...

And as Stefano Borini mentions,

[if] you have a module so large that you feel compelled to add ONLY, it means that your module is too big. Split it.

Gaelan answered 6/8, 2009 at 18:6 Comment(2)
One of the problems with Fortran is that when you import from modules you will always throw everything in the global namespace, as in Javascript. In python, you can do from foo.bar import *, but also from foo import bar. In fortran, you have no choice. Every time you use USE, you are doing a import *, and including everything into the global namespace. This is one of the worst Fortran 9X issues.Locoism
@StefanoBorini: does that last sentence imply that the problem is resolved in more recent fortran versions?Mandler
L
18

It's a matter of balance.

If you use only a few stuff from the module, it makes sense if you add ONLY, to clearly specify what you are using.

If you use a lot of stuff from the module, specifying ONLY will be followed by a lot of stuff, so it makes less sense. You are basically cherry-picking what you use, but the true fact is that you are dependent on that module as a whole.

However, in the end the best philosophy is this one: if you are concerned about namespace pollution, and you have a module so large that you feel compelled to add ONLY, it means that your module is too big. Split it.

Update: Fortran? just recode it in python ;)

Locoism answered 6/8, 2009 at 18:21 Comment(1)
This is a useful heuristic for "how large should my module be?".Orthopterous
O
29

I used to just do use modulename - then, as my application grew, I found it more and more difficult to find the source to functions (without turning to grep) - some of the other code floating around the office still uses a one-subroutine-per-file, which has its own set of problems, but it makes it much easier to use a text editor to move through the code and quickly track down what you need.

After experiencing this, I've become a convert to using use...only whenever possible. I've also started picking up Python, and view it the same way as from modulename import *. There's a lot of great things that modules give you, but I prefer to keep my global namespace tightly controlled.

Orthopterous answered 6/8, 2009 at 18:51 Comment(2)
I like your analogy to importing Python Modules--good thinking!Gaelan
Exactly. I only use the explicit import "use ... only" just like in Python I only use "from ... import". I think this is the right approach.Below
L
18

It's a matter of balance.

If you use only a few stuff from the module, it makes sense if you add ONLY, to clearly specify what you are using.

If you use a lot of stuff from the module, specifying ONLY will be followed by a lot of stuff, so it makes less sense. You are basically cherry-picking what you use, but the true fact is that you are dependent on that module as a whole.

However, in the end the best philosophy is this one: if you are concerned about namespace pollution, and you have a module so large that you feel compelled to add ONLY, it means that your module is too big. Split it.

Update: Fortran? just recode it in python ;)

Locoism answered 6/8, 2009 at 18:21 Comment(1)
This is a useful heuristic for "how large should my module be?".Orthopterous
V
7

Not exactly answering the question here, just throwing in another solution that I have found useful in some circumstances, if for whatever reason you don't want to split your module and start to get namespace clashes. You can use derived types to store several namespaces in one module.

If there is some logical grouping of the variables, you can create your own derived type for each group, store an instance of this type in the module and then you can import just the group that you happen to need.

Small example: We have a lot of data some of which is user input and some that is the result of miscellaneous initializations.

module basicdata
   implicit none
   ! First the data types...
   type input_data
      integer :: a, b
   end type input_data
   type init_data
      integer :: b, c
   end type init_data

   ! ... then declare the data
   type(input_data) :: input
   type(init_data) :: init
end module basicdata

Now if a subroutine only uses data from init, you import just that:

subroutine doesstuff
   use basicdata, only : init
   ...
   q = init%b
end subroutine doesstuff

This is definitely not a universally applicable solution, you get some extra verbosity from the derived type syntax and then it will of course barely help if your module is not the basicdata sort above, but instead more of a allthestuffivebeenmeaningtosortoutvariety. Anyway, I have had some luck in getting code that fits easier into the brain this way.

Vries answered 11/3, 2011 at 8:10 Comment(0)
P
4

The main advantage of USE, ONLY for me is that it avoids polluting my global namespace with stuff I don't need.

Powerful answered 6/8, 2009 at 18:16 Comment(0)
B
1

Agreed with most answers previously given, use ..., only: ... is the way to go, use types when it makes sense, apply python thinking as much as possible. Another suggestion is to use appropriate naming conventions in your imported module, along with private / public statements.

For instance, the netcdf library uses nf90_<some name>, which limits the namespace pollution on the importer side.

use netcdf  ! imported names are prefixed with "nf90_"

nf90_open(...)
nf90_create(...)
nf90_get_var(...)
nf90_close(...)

similarly, the ncio wrapper to this library uses nc_<some name> (nc_read, nc_write...).

Importantly, with such designs where use: ..., only: ... is made less relevant, you'd better control the namespace of the imported module by setting appropriate private / public attributes in the header, so that a quick look at it will be sufficient for readers to assess which level of "pollution" they are facing. This is basically the same as use ..., only: ..., but on the imported module side - thus to be written only once, not at each import).

One more thing: as far as object-orientation and python are concerned, a difference in my view is that fortran does not really encourage type-bound procedures, in part because it is a relatively new standard (e.g. not compatible with a number of tools, and less rationally, it is just unusual) and because it breaks handy behavior such as procedure-free derived type copy (type(mytype) :: t1, t2 and t2 = t1). That means you often have to import the type and all would-be type-bound procedures, instead of just the class. This alone makes fortran code more verbose compared to python, and practical solutions like a prefix naming convention may come in handy.

IMO, the bottom line is: choose your coding style for people who will read it (this includes your later self), as taught by python. The best is the more verbose use ..., only: ... at each import, but in some cases a simple naming convention will do it (if you are disciplined enough...).

Bondstone answered 12/12, 2015 at 11:58 Comment(0)
R
1

Yes, please use use module, only: .... For large code bases with multiple programmers, it makes the code easier to follow by everyone (or just use grep).

Please do not use include, use a smaller module for that instead. Include is a text insert of source code which is not checked by the compiler at the same level as use module, see: FORTRAN: Difference between INCLUDE and modules. Include generally makes it harder for both humans and computer to use the code which means it should not be used. Ex. from mpi-forum: "The use of the mpif.h include file is strongly discouraged and may be deprecated in a future version of MPI." (http://mpi-forum.org/docs/mpi-3.1/mpi31-report/node411.htm).

Riker answered 9/5, 2016 at 12:59 Comment(3)
Do not add the sentences like the first one in your second paragraph. Either your answer is suitable as a standalone answer or it isn't and then don't post it. Get the rep first to post the comments, it is easy. With sentences like that you only invite people to vote for your question to be deleted. There is a special delete reason fr such answers/comments.Aleksandrovsk
@VladimirF and that is a good idea and valid reason for deleting. I came across this by chance and assuming I would forget I decided to post because I think the use of include is such bad practice it should be deprecated, at least actively discouraged. It generally makes it harder for both humans and computer and then it should not be used. Ex from mpi-forum: "The use of the mpif.h include file is strongly discouraged and may be deprecated in a future version of MPI." (mpi-forum.org/docs/mpi-3.1/mpi31-report/node411.htm). So I gave a valid answer and added a remark. Edited post.Riker
I agree. You can put this quote into the answer. Unfortunately, the OpenMPI manual still shows only include mpif.h before every subroutine manual entry, at least in version 1.8.Aleksandrovsk
M
0

I know I'm a little late to the party, but if you're only after a set of constants and not necessarily computed values, you could do like C and create an include file:

inside a file, e.g., constants.for

real, parameter :: pi = 3.14
real, parameter :: g = 6.67384e-11
...


program main
    use module1, only : func1, subroutine1, func2 
    implicit none

    include 'constants.for'
    ...
end program main

Edited to remove "real(4)" as some think it is bad practice.

Manyplies answered 20/11, 2014 at 22:15 Comment(2)
Please, do not teach the people the bad habit of using real(4) when the original question doesn't require it. Also, I can't agree that the include approach is better or even simpler.Aleksandrovsk
real(4) is copy/paste and force of habit on my end. I thought about your other comment but I left it in anyway. There's myriad ways people can accomplish the same thing. It's important that people experiment and find what they like. In my opinion and "include" file would only be more difficult if he/she weren't using a Makefile and didn't add the "-I."Manyplies

© 2022 - 2024 — McMap. All rights reserved.