15429

variable length array in derived type

Question:

I am mostly doing scientific programming in Python and do not have a whole lot of Fortran (90/95) experience. For one of my projects I want to define a derived type and overload a bunch of operators for that type. Critically, I'd like one of the variables of the derived type to an array of variable length; at least, I need two different lengths in different parts of the code. How can I best achieve this efficiently and avoiding code duplication?

My first approach was to use an allocatable array but that involved several allocate statements throughout the code including the overloaded operators. It also led to difficulties when using the code in an MPI application.

My current approach is two define a type of the same name in two separate modules and use one or the other in different parts of the code. The overloaded operators can be shared using a header file (mytype_operators.h in the example below).

module mod1 type mytype real :: x1 real,dimension(1) :: x2 end type mytype #include "mytype_operators.h" end module mod1 module mod2 type mytype real :: x1 real,dimension(10) :: x2 end type mytype #include "mytype_operators.h" end module mod2

Unfortunately, there is one module in the code with subroutines that I would like to use for both types. Currently I have two copies of that code; one with "use mod1", the other with "use mod2". Can I improve this and avoid the code duplication?

Answer1:

Your case is very suitable for using a Fortran feature introduced in the 2003 standard (and adopted much later by compilers) named <a href="https://software.intel.com/en-us/node/692037" rel="nofollow">parameterized derived types</a>. First of all, you should check the compliance status of your compiler to know if it's fully supported.

This feature allows you to pass custom parameters when declaring or constructing a derived-type, so internal functionality will be adjusted accordingly. They are good for having different behaviour alternatives grouped in a single type name, possibly with considerable coding or storage differences. There are 2 types of parameters:

<ul><li>kind parameters behave much like the kind specifier of intrinsic types. Kind parameters of all variables must be known at compile time and are treated practically as constant values. The convenience is that you could change it easily (in code time) by altering just a value in the declaration or construction. This is commonly used for specializing the kind of components of intrinsic type.</li> <li>len parameters behave much like the len specifier of intrinsic character type. You can define len parameters at compile time or runtime, and a len parameter of a variable cannot change unless you declared it allocatable. Moreover, you can have arguments with assumed len-parameters in procedures, and avoid code verbosity. This is commonly used as a "length" or "dimension" parameter for a derived type, because you can use them in the declaration of array bounds and character length.</li> </ul>

In general, type parameters are used to mimic the functionality of intrinsic types in derived types, but you could also get "creative" and use it for other things, like the dimension-space of a transformation-matrix type; for a custom "union type" (like an enumeration); as the nature of a physical quantity in a "units of measurement" data-type (a real value annotated with "mass" unity is not directly compatible with a "temperature" one, but they can be handled pretty much the same way in the code); the "arity" of a tuple type...

module mod1 type :: mytype(n) integer, len :: n real :: x1 real, dimension(n) :: x2 end type mytype contains ! your operations here... end module mod1

And use it like this:

program test_pdt use mod1 implicit none type(mytype(10)) :: mt10 type(mytype(1)) :: mt1 integer :: i mt10%x1 = 40.0 mt10%x2 = [(0.5 * i, i = 1, 10)] mt1 = mytype(1)(20.0, [30.0]) call sub(mt10) call sub1(mt1) contains subroutine sub(m) ! accepts values with any "n" parameter type(mytype(*)) :: m ! you can also use them in declarations integer, dimension(m%n + 1) :: y type(mytype(m%n)) :: w print *, m%n, w%n, size(y) end subroutine sub1(m) type(mytype(1)) :: m ! only accepts values with n=1 print *, m%x1, m%x2, m%n end end <hr />

Warning: This is feature, despite of having been announced many years ago, was just recently added to most compilers, and you should be aware that there are still some bugs in implementation. You should probably be fine with regular use, but I often face false syntax errors in some corner cases, and even ICE sometimes.

Recommend

  • Cannot run nunit tests with Nant
  • WPF and background worker and the calling thread must be STA
  • Docker container doesn't start, showing as 'Exited n seconds ago'
  • Building a dynamic query in C# (SQL Injection Attack)
  • How to pass string and dictionary in NUnit test cases?
  • C# OpenFileDialog Thread start but dialog not shown
  • Entity Framework and the raw string query - SQL injection prevention
  • How to improve this function?
  • Haskell: List Created Evaluating List Elements
  • Is there a pre-defined built-in function to convert a number to its binary format in C++?
  • Index on every Foreign Key?
  • Const variable in C++ function body
  • Javascript and VERY LONG string
  • JHipster Entity Generator crahing
  • Get entry assembly from ASP.NET application [duplicate]
  • SQL Server: +(unary) operator on non-numeric Strings
  • git cherry-pick: how consider only lines modified by the commit (i.e., not the surrounding context)?
  • ASP.NET, C# How to Pass a StringQuery to a custom SQL Command
  • Adding independent aspx/asmx pages into DotNetNuke
  • Update varbinary(MAX) field in SQLServer 2012 Lost Last 4 bits
  • What does “t” refer to in this SQL?
  • CERN ROOT exporting data to plain text
  • Object and struct member access and address offset calculation
  • how to avoid repetitive constructor in children
  • Django simple Captcha “No module named fields” error
  • Sort List of Strings By Version
  • How to get Eclipse Oxygen to run on Java 9
  • Abort upload large uploads after reading headers
  • Why does access(2) check for real and not effective UID?
  • Control modification in presentation layer
  • java.lang.NoClassDefFoundError: com.parse.Parse$Configuration$Builder on below Lollipop versions
  • What is Eclipse's Declaration View used for?
  • How to make Safari send if-modified-since header?
  • How to pass list parameters for each object using Spring MVC?
  • Linker errors when using intrinsic function via function pointer
  • WPF Applying a trigger on binding failure
  • how does django model after text[] in postgresql [duplicate]
  • Setting background image for body element in xhtml (for different monitors and resolutions)
  • JaxB to read class hierarchy
  • jQuery Masonry / Isotope and fluid images: Momentary overlap on window resize