- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dear Intel developer,
The ifort 16 compiler (16.0.0 20150815) seems to generate non-standard conforming code, when a polymorphic type with an overriden operator is stored as a pointer within a derived type. The self containing example below demonstrates the issue for the comparison operator: the code calls the comparison operator of the basetype, instead of the extended one. Similar error happens if the assignment operator is overriden, so I guess, the problem is operator independent.
Best regards,
Bállint
module typedefs implicit none type :: Base contains procedure :: isEqualTo => Base_isEqualTo generic :: operator(==) => isEqualTo end type Base type, extends(Base) :: Extended integer :: data contains procedure :: isEqualTo => Extended_isEqualTo end type Extended contains function Base_isEqualTo(this, other) result(isEqual) class(Base), intent(in) :: this class(Base), intent(in) :: other logical :: isEqual select type (other) type is (Base) isEqual = .true. class default isEqual = .false. end select print *, "Base_isEqualTo:", isEqual end function Base_isEqualTo function Extended_isEqualTo(this, other) result(isEqual) class(Extended), intent(in) :: this class(Base), intent(in) :: other logical :: isEqual select type (other) type is (Extended) isEqual = (this%data == other%data) class default isEqual = .false. end select print *, "Extended_isEqualTo:", isEqual end function Extended_isEqualTo end module typedefs program test use typedefs implicit none type :: BasePtr class(Base), pointer :: ptr end type BasePtr type(Extended) :: myExt1, myExt2 logical :: isEqual type(BasePtr), allocatable :: array(:) myExt1%data = 1 myExt2%data = 1 allocate(array(2)) allocate(array(1)%ptr, source=myExt1) allocate(array(2)%ptr, source=myExt2) ! This should invoke Extended_isEqualTo, but it calls Base_isEqualTo instead isEqual = (array(1)%ptr == array(2)%ptr) print *, "Main:", isEqual end program test
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm not convinced it is an issue with the compiler. Prima facie, Intel Fortran appears standard-conforming even though it doesn't work as you want it to whereas gfortran does. I vaguely recall discussions along these lines on this forum and elsewhere; I'm unable to track down any details at present. But perhaps you can follow up with the standard and point to relevant sections that indicate the behavior should be as you indicate. Given the polymorphic pointer component, I think the standard requires you to do something along the following lines given how you have defined the Base and Extended types and in that case, Intel compiler will work as you would like it to:
program test use typedefs implicit none type :: BasePtr class(Base), pointer :: ptr end type BasePtr type(Extended) :: myExt1, myExt2 logical :: isEqual type(BasePtr), allocatable :: array(:) myExt1%data = 1 myExt2%data = 1 allocate(array(2)) allocate(array(1)%ptr, source=myExt1) allocate(array(2)%ptr, source=myExt2) select type ( ptr => array(1)%ptr ) type is ( Extended ) isEqual = (ptr == array(2)%ptr) class default isEqual = (array(1)%ptr == array(2)%ptr) end select print *, "Main:", isEqual end program test
Upon execution with Intel Fortran,
Extended_isEqualTo: T Main: T Press any key to continue . . .
Of course, the above change is lame but I think that is what it would take with polymorphic components of the 'class(Base)', a penalty incurred with runtime polymorphism. But I may be wrong about this, would like to learn better.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm looking at this. I think it should work. More later.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I am quite bad in reading the words of the standard, so I can not point out which part of it is violated by the code above. Thanks for the working example. Actually, although it may work fine, I really need run-time polymorphism, as I am designing collections with elements of arbitrary types.
Also, note, that if I replace the call
isEqual = (array(1)%ptr == array(2)%ptr)
with
isEqual = array(1)%ptr%isEqualTo(array(2)%ptr)
(without any select type statement around) the code works as expected. So, ifort knows how to do proper run-time polymorphism, but forgets it, if it is invoked via an overridden operator.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I think this is the same general issue as https://software.intel.com/en-us/forums/intel-fortran-compiler-for-linux-and-mac-os-x/topic/623372
Here is what the standard says regarding defined operators:
5 A function defines the binary operation x1 op x2 if (1) the function is specified with a FUNCTION (12.6.2.2) or ENTRY (12.6.2.6) statement that specifies two dummy arguments, d1 and d2, (2) either (a) a generic interface (12.4.3.2) provides the function with a generic-spec of OPERATOR (op), or (b) there is a generic binding (4.5.5) in the declared type of x1 or x2 with a generic-spec of OPERATOR (op) and there is a corresponding binding to the function in the dynamic type of x1 or x2, respectively, (3) the types of d1 and d2 are compatible with the dynamic types of x1 and x2, respectively, (4) the type parameters, if any, of d1 and d2 match the corresponding type parameters of x1 and x2, respectively, and (5) either (a) the ranks of x1 and x2 match those of d1 and d2 or (b) the function is elemental, x1 and x2 are conformable, and there is no other function that defines the operation.
In this case, there is a generic-spec of OPERATOR(op) and a corresponding binding in the dynamic type of array()%ptr. I added this to DPD200409351.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page