Software Archive
Read-only legacy content
17061 Discussions

DEFINED OPERATORS/INTERFACE

paulw
Beginner
692 Views
The examples of how to define your own binary operator in the
language reference (example operators .BAR. and "+") omit to show
where you put the executable lines of code that perform the
function (section 8.9.4). I have tried placing the executable lines of
code in every conceivable place

(e.g. between "FUNCTION MYFUNC(A,B)"
and "END FUNCTION MYFUNC" , which seems logical)

but the compiler kicks it out or says I haven't defined the operator.

Lets look at the .BAR. example provided:

INTERFACE OPERATOR(.BAR.)
FUNCTION BAR(A_1)
INTEGER, INTENT(IN) :: A_1
INTEGER :: BAR
END FUNCTION BAR
END INTERFACE

Then it is said you invoke the function when you write

I=4 + (.BAR.B)

But nowhere is it defined what .BAR. does!

Does it square B? Does it do a 1's complement of B?

There has a place to put the executable code that defines what it
does, but the compiler will not accept executable code in an
INTERFACE block, only declarations.

Can anyone provide a clue?

Thanks,
Paul Dent
0 Kudos
5 Replies
Jugoslav_Dujic
Valued Contributor II
692 Views
Hi Paul,

INTERFACE block is function declaration, i.e. the place where you tell compiler how the specific function is called; the same holds for INTERFACE OPERATOR - you tell compiler to "replace" operator .BAR. in the current procedure with a specific function. The definition, i.e. the body of the function is somewhere else.

So, in non-MODULE style of programming, INTERFACE OPERATOR should be placed in the declaration part of the routine that uses the operator .BAR.
If it's needed in several places, you can put it in an INCLUDE (.fi) file.
FUNCTION BAR itself can be placed in any source file of the project.

Otherwise, if you put function BAR in a module, the INTERFACE OPERATOR should be placed in declaration part of the module (above CONTAINS statement). The full description in the INTERFACE is not needed; use MODULE PROCEDURE instead:

 
 
MODULE FOO 
 
INTERFACE OPERATOR (.BAR.) 
MODULE PROCEDURE BAR 
END INTERFACE 
 
CONTAINS 
 
FUNCTION BAR(A_1) 
...(do something) 
END FUNCTION BAR 
 
END MODULE FOO 


HTH
Jugoslav
0 Kudos
paulw
Beginner
692 Views
Thanks for your input Jugoslav. What you suggest does work, but only
when the function and the operator are defined to operate on standard
variable types, and does not work for user-defined variable type.
I e-mailed you the following example, where all I did was change the
variable type from REAL A(2) to

TYPE ARRAY2
REAL C(2)
END TYPE ARRAY2
TYPE(ARRAY2) A,B

Here is the programme that works:

C*************MAIN PROGRAM********************
C****DEFINE OPERATOR INTERFACE*****
INTERFACE OPERATOR(.MULT.)
FUNCTION MUL(A,B)
REAL,INTENT(IN) :: A(2),B(2)
REAL MUL(2)
END FUNCTION MUL
END INTERFACE
REAL A(2),B(2),X(2)
A(1)=1.0
A(2)=0.5
B(1)=2.0
B(2)=0.6
C USE THE OPERATOR
X=A.MULT.B
C AND PRINT THE RESULT WHICH SHOULD BE 2.0, -0.3
WRITE(*,*)X
STOP
END
C**CODE THAT IMPLEMENTS THE OPERATOR .MULT.***
FUNCTION MUL(A,B)
REAL A(2),B(2),MUL(2),X(2)
X(1)=A(1)*B(1)
X(2)=-A(2)*B(2)
MUL=X
END FUNCTION MUL

and here is the version that does not compile:

C*******************MAIN PROGRAM********************
C**DECLARE SOME VARIABLES OF A USER-DEFINED TYPE**
TYPE ARRAY2
REAL C(2)
END TYPE ARRAY2
TYPE(ARRAY2) A,B,X
C**DECLARE THE INTERFACE FOR THE OEPRATOR .MULT.***
INTERFACE OPERATOR(.MULT.)
FUNCTION MUL(A,B)
TYPE ARRAY2
REAL C(2)
END TYPE ARRAY2
TYPE(ARRAY2),INTENT(IN) :: A,B
TYPE(ARRAY2) MUL
END FUNCTION MUL
END INTERFACE
C***NOW TRY TO USE THE DEFINED OPERATOR***
A.C(1)=1.0
A.C(2)=0.5
B.C(1)=2.0
B.C(2)=0.6
X=A.MULT.B
WRITE(*,*)X
STOP
END
C**CODE THAT IMPLEMENTS THE OPERATOR .MULT.***
FUNCTION MUL(A,B)
TYPE ARRAY2
REAL C(2)
END TYPE ARRAY2
TYPE(ARRAY2) A,B,MUL,X
X.C(1)=A.C(1)*B.C(1)
X.C(2)=-A.C(2)*B.C(2)
MUL=X
END FUNCTION MUL

Surely the compiler lets us define operators for operating on user
defined types? That's the whole point! What am I missing?

Paul
0 Kudos
Jugoslav_Dujic
Valued Contributor II
692 Views
Hi Paul,
The source you posted is almost good; I thought it would have worked, but it didn't. The problem is in the scope of declaration of type ARRAY2; it isn't "seen" the same within PROGRAM and INTERFACE. Here's the correct code that works (it looks as if the MODULEs have to be involved; but then, generic operators are also Fortran-90 stuff). Perhaps someone more versed in standards issues might explain why the code you posted does not work:

 
MODULE OVRMOD 
 
TYPE ARRAY2  
REAL C(2)  
END TYPE ARRAY2  
 
END MODULE OVRMOD 
!=============================== 
PROGRAM OVERLOAD 
USE OVRMOD 
 
TYPE(ARRAY2) A,B,X  
 
!**DECLARE THE INTERFACE FOR THE OEPRATOR .MULT.***  
INTERFACE OPERATOR (.MULT.)  
   FUNCTION MUL(A,B) RESULT(F)  
   USE OVRMOD 
   TYPE(ARRAY2),INTENT(IN) :: A,B  
   TYPE(ARRAY2) F  
   END FUNCTION MUL  
END INTERFACE  
!***NOW TRY TO USE THE DEFINED OPERATOR***  
A.C(1)=1.0  
A.C(2)=0.5  
B.C(1)=2.0  
B.C(2)=0.6  
X=A.MULT.B 
  
WRITE(*,*)X  
STOP  
END  
!=============================== 
FUNCTION MUL(A,B) RESULT(F)  
USE OVRMOD 
 
TYPE(ARRAY2),INTENT(IN) :: A,B  
TYPE(ARRAY2) F 
 
DO I=1,2 
   F.C(I)=A.C(I)*B.C(I) 
END DO 
 
END FUNCTION MUL  
 


Regards

Jugoslav
0 Kudos
paulw
Beginner
692 Views
Thanks for your help, Jugoslav. It works now - why it is essential to use
the MODULE construction is a puzzle, and it is very fussy about the order
of things.

My next problem is that I can write user defined operators for doing
arithmetic on user defined types that work one a time, i.e I can write

F=A*B
F=A+B
F=A-B
F=F+A etc
and they all work according to the function definitions I have provided

However, if I write

F=A*B+C

which I hoped to do, or even

F = (A*B)+C

I get garbage, and the reason seems to be that the compiler is not
allocating the right "shape" of storage for the intermediate result of A*B

Do you know if one is supposed to be able to write expressions of
any complexity, with nested parentheses etc with user-defined
operators, or not?

Thanks,
Paul
0 Kudos
Intel_C_Intel
Employee
692 Views
Derived type definitions have to either come from the same source (USE or host association) or be SEQUENCE derived types and be otherwise identical. It seems to me much simpler to define the type in a module and use the module where the type is required; you don't have to maintain several identical derived type definitions throughout your code. Look in the online docs under Derived type statement, Rules and Behavior. The problem you may be having with statements like F = A*B+C is that the output of your binary multiplication operator isn't the same as the left input to your addition operator. This should give you errors at compile time rather than garbage, however. Now, if the object in question are arrays rather than derived types, you could have a problem if the lengths aren't conformable. You could check this possibility by making the inputs assumed shape arrays and then comparing their lengths within the function.
0 Kudos
Reply