Zeus
Zeus

Reputation: 1545

Fortran: Accessing values from the return type of a function

I have created a derived type V, and included an add function so that I can use the operator +.

However when I do

z = u + v

the operation is not performed. I think it is because z%kn is not being accessed.

However when I do

Call vsum(z, u, v) 

everything works as expected

Below is the declaration of the derived type and the overloading function vadd.

Module vtest

Type :: V

  Character (Len=8) :: kn
  Real,  Allocatable :: vc(:)

  Contains

    Procedure :: vadd
    Generic :: Operator (+) => vadd

 End Type vtest

Contains

Function vadd (b, c) Result (a)
  Type (V) :: a
  Class (V), Intent (In) :: b, c

  !!$ In vsum, use is made of a% kn 
  Call vsum (a, b, c)

End Function vadd

 Subroutine vsum (ta, tb, tc)
   Type (V), Intent (InOut)  :: ta
   Type (V), Intent (In) :: tb, tc

   Logical :: la, lb, lc

   la = .False.;  lb = .False.;  lc = .False.

   Select Case (ta%kn) 

   Case ("Real32")
     If (Allocated (ta%vc)) la = .True.
     If (Allocated (tb%vc)) lb = .True.
     If (Allocated (tc%vc)) lc = .True.
     If (la .And. lb .And. lc) Then 
       ta%vc = tb%vc + tc%vc
     End If

   End Select

 End Subroutine vsum

End Module vtest


Program test
Use vtest
Type (V) :: z

   z% kn = "Real32"
   Allocate (z% vc_real32(3))
   Write (*,*) "z = u + v"
   Write (*,*) "z% kn: ", z% kn
   z = u + v
   Write (*,*) "z% kn: ", z% kn
   Write (*,*) "z: ", z% vc_real32

End Program vtest

Upvotes: 1

Views: 76

Answers (1)

francescalus
francescalus

Reputation: 32406

Let's look at the subroutine vsum. The work that is done in that subroutine depends on the definition of the components of all three objects ta, tb and tc. For your summation to proceed as you expect it is necessary for all the allocatable components to be allocated and for the match of ta%kn with 'Real32'.

There's no complete working example, but as you say things work when there is a call like

call vsum(z, u, w)  ! V is the name of the type, so call the variable w

z%kn is set to 'Real32'.

However, with the defined operation

z = u + w

there is the function reference

z = vadd(u, w)

in which there is the call

call vsum (a, b, c)  ! Actual arguments "z", u, w.

Now, a is the function result of vadd. Consequent of this is that, just like a dummy argument with intent(out) a is initially undefined.

That means, essentially, when passed through vadd z makes it to vsum with undefined component kn and unallocated component vc. So, the requirements for the summation are not met (and indeed the select case forms an invalid reference).


I suppose I can comment on how to fix this issue, also.

In vsum, you're taking, in effect, the type of operation from the "result". Instead, something like

Subroutine vsum (ta, tb, tc)
  Type (V), Intent (Out)  :: ta
  Type (V), Intent (In) :: tb, tc

  Logical :: lb, lc

  lb = .False.;  lc = .False.

  ! In here we probably want some consistency checking...
  Select Case (tb%kn)    
  Case ("Real32")
    If (Allocated (tb%vc)) lb = .True.
    If (Allocated (tc%vc)) lc = .True.
    If (lb .And. lc) Then 
      ta%vc = tb%vc + tc%vc   ! ta%vc being automatically allocated
    End If
  End Select

 End Subroutine vsum

This, naturally, doesn't address your seeming desire (from the title) to take the type of operation from the result. You could do that with your original subroutine approach, but except in one instance that isn't the philosophy of Fortran functions.

If you want to use defined operations, then you can't have the operation defined by the left-hand side of the assignment. In an expression u+w there isn't a left-hand side, but the defined operation is still expected to behave. That is also to say, in the statement

z = u + w

you aren't saying "z is the result of the operation + applied to u and w". But: "the operation + applied to u and w is evaluated and the result (through defined or implicit assignment) assigned to z". There is that assignment before the "type of the result" is reached. This is why earlier on I put z as the actual argument in quotes.

Upvotes: 2

Related Questions