Dear Malcolm!
Thanks a million for your very detailed explanations. It helped me much
understanding the problem and its solution.
And btw. you are right. nag obviously rejected the the code I wrote.
While playing around with all that I simply confused this.
Thanks again! Cheers, Stefan
Am 2013-12-04 03:04, schrieb Malcolm Cohen:
> Hi Stefano,
>
>> I ran into some troubles understanding how type bound operator
>> overloading works.
> ...
>> The issue is that I don not know if the attached code is valid
>> Fortran.
>
> It is not.
>
>> Some compilers as intel and nag
>
> The NAG compiler rejects your program with
>
> Error: sk9b.f90, line 34: Ambiguous specific type-bound procedures
> EQ_EXTENSION and EQ_BASE for type-bound generic OPERATOR(.EQ.) in type
> BASE
>
> Both the ancient 5.2 release and the more recent 5.3.1 release reject
> this with the same message...
>
>> Could you help me out to understand how operator overloading works
>> properly?
>
> Since you are trying to do something that would be inherently
> ambiguous - CLASS(base) accepts everything that CLASS(extension)
> accepts - you need to use overriding (and thus dynamic dispatch) to
> get the result you want. Overriding only solves this for one argument
> though, handling the second argument is best done with type enquiry.
>
>> MODULE my_mod
>>
>> TYPE :: base
>> INTEGER :: a
>> CONTAINS
>> PROCEDURE, PRIVATE :: eq_base
>> GENERIC, PUBLIC :: OPERATOR(==) => eq_base
>> END TYPE
>>
>> TYPE, EXTENDS(base) :: extension
>> INTEGER :: b
>> CONTAINS
> REPLACE> PROCEDURE, PRIVATE :: eq_extension
> PROCEDURE,PRIVATE :: eq_base => eq_extension
>
> DELETE > GENERIC, PUBLIC :: OPERATOR(==) => eq_extension
>
>> END TYPE
>
> COMMENT: This makes eq_base (and thus ==) dispatch to eq_base when the
> first argument is TYPE(base), and eq_extension when the first argument
> is TYPE(extension). Handling the second argument is best done within
> those routines.
>
>> CONTAINS
>>
>> ELEMENTAL LOGICAL FUNCTION eq_base(c1, c2)
>> CLASS(base), INTENT(IN) :: c1, c2
> REPLACE> eq_base = .FALSE.
> REPLACE> IF (c1%a/=c2%a) RETURN
> REPLACE> eq_base = .TRUE.
>
> eq_base = SAME_TYPE_AS(c1,c2) .AND. c1%a==c2%a
>
>> END FUNCTION
>>
>> ELEMENTAL LOGICAL FUNCTION eq_extension(c1, c2)
> REPLACE> CLASS(extension), INTENT(IN) :: c1, c2
>
> CLASS(extension),INTENT(IN) :: c1
> CLASS(base),INTENT(IN) :: c2
>
> COMMENT: c2 needs to be declared CLASS(base) because
> (1) it was declared CLASS(base) in eq_base ... only the "passed
> object" dummy varies the type;
> (2) so it can handle "extension==base".
>
> REPLACE> eq_extension = .FALSE.
> REPLACE> IF (.NOT.(c1%base==c2%base)) RETURN
> REPLACE> IF (c1%b/=c2%b) RETURN
> REPLACE> eq_extension = .TRUE.
>
> IF (.NOT.SAME_TYPE_AS(c1,c2)) THEN
> eq_extension = .FALSE.
> ELSE
> SELECT TYPE(c2)
> CLASS IS (extension) ! Guaranteed to execute since same type.
> eq_extension = c1%a==c2%a .AND. c2%b==c2%b
> END SELECT
> END IF
>
> COMMENT: The SELECT TYPE is to get access to the components of c2
> added by the type "extension", i.e. to c2%b.
>
>> END FUNCTION
>>
>> END MODULE
>>
>> PROGRAM main
>>
>> USE my_mod
>>
>> TYPE(base) :: b = base(1)
>> TYPE(extension) :: e = extension(1,2)
>>
>> PRINT *, b == b ! => T
>> PRINT *, base(2) == e ! => F
>> PRINT *, e == base(2) ! => F
>> PRINT *, e == e ! => T
>>
>> END PROGRAM
>
> With these changes, your program prints "T F F T" (on 4 lines) with
> the current NAG compiler release (5.2 did not have the SAME_TYPE_AS
> intrinsic).
>
> Cheers,
|