Reputation: 1545
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
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