JohnE
JohnE

Reputation: 30424

Referencing a function that returns a structure/derived type

I'm struggling with a concise title, but it's not that complicated. I have a function that returns a structure (derived type) and I'm looking for a simple way to reference only a part of the structure while calling the function (without copying/pointing to another structure).

program main

   real :: xx = 1.
   real :: yy = 2.

   ! works fine but what I want is to be 
   ! able to return %tx and %ts separately

   print *, " tax ", tax(xx,yy)

   ! just guessing at possible syntax here, but neither works

   print *, " tax ", tax%tx(xx,yy)
   print *, " tax ", tax(xx,yy)%tx

contains

function tax(x,y)

   real :: x, y

   type tTax
      real :: tx, ty
   end type tTax

   type(tTax) :: tax

   tax%tx = x * 100.
   tax%ty = y * 100.

end function tax

end program main

I'm restricted to f90/f95 feature set but feel free to include f2003 answers also.

And I'm really looking for something simple here, if it exists. Otherwise, it's just going to be better to do as a subroutine (if the alternative is keeping it as a function but adding pointers, interfaces, etc.).

I also tried having the function return a 2 dimensional array instead of a structure and had the same basic problem -- it works, but I am only able to print the whole array, not any array sections by themselves.

I had trouble even guessing at the syntax there since () is used for both functions and array sections in fortran (as opposed to languages like python which uses [] for indexing, so it's fairly natural to mix functions and indexes e.g. something like tax(xx,yy)[1,:]).

Upvotes: 2

Views: 1510

Answers (2)

The problem is not in the parenthesis symbols, it is just whether you are allowed to reference a component or element of an expression or not.

And in Fortran you are not allowed that. You can only use the % syntax or array indexing () on variable or constant names or on associate-names.

Upvotes: 3

jlokimlin
jlokimlin

Reputation: 593

You can create a user-defined constructor by overloading the derived-data type's name with a function return.

Liberal use of the Fortran 2003 standard's associate construct allows one to access specific type-components without copying or resorting to memory-leak-prone pointers.

Is there any particular reason why you're restricting yourself to Fortran 2003; a great deal of Fortran 2008 is supported by most popular compilers.

The following code

module mymod

  ! Explicit typing only
  implicit none

  ! Declare derived data type
  type tTax
     real :: tx, ty
  end type tTax

  ! User-defined constructor
  interface tTax
     module procedure tax
  end interface tTax

contains

  function tax(x, y) result (return_value)
    real, intent (in) :: x, y
    type (tTax)       :: return_value

    return_value%tx = x * 100.0
    return_value%ty = y * 100.0

  end function tax

end module mymod

program main

  use mymod

  ! Explicit typing only
  implicit none

  real       :: xx = 1.0, yy = 2.0
  type(tTax) :: foo

  print *, " tax ", tax(xx,yy)
  print *, " tax ", tTax(xx, yy)

  ! Invoke the user-defined constructor
  foo = tTax(xx, yy)

  ! Fortran 2003's associate construct
  associate( &
       tx => foo%tx, &
       ty => foo%ty &
       )
       print *, " tax ", tx, ty
  end associate

end program main

yields

gfortran -Wall -o main.exe mymod.f90 main.f90
./main.exe
  tax    100.000000       200.000000    
  tax    100.000000       200.000000    
  tax    100.000000       200.000000 

Upvotes: 3

Related Questions