Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

polymorphic variables: assignment "poly = a" and "a = poly"

riad_h_1
Beginner
514 Views

Hello, I'm discovering the pleasures of the OOP and I'm faced with a problem depending on the compiler (ifort vs gfortran).  Consider this first simple module:

module typedefs
   implicit none
   
   type base_t
      integer :: i = 0
   end type base_t
   
   type, extends(base_t) :: ext1_t
      integer :: j = 0
   contains
      procedure :: ext1EqCl
      generic :: assignment(=) => ext1EqCl    
   end type ext1_t
      
   interface assignment(=)
      module procedure generic_assign
   end interface

contains     
    
   subroutine generic_assign (lhs, rhs)
      class(base_t), intent(in )              :: rhs
      class(base_t), intent(out), allocatable :: lhs
      print*,'--> generic_assign'
      allocate (lhs, source=rhs)
   end subroutine generic_assign

   subroutine ext1EqCl (lhs, rhs)
      class(base_t), intent(in ) :: rhs
      class(ext1_t), intent(out) :: lhs
      print*,'--> ext1EqCl'
      select type(rhs)
         type is (ext1_t)
            lhs%i = rhs%i ; lhs%j = rhs%j
      end select      
   end subroutine ext1EqCl
   
end module typedefs

program test

   use typedefs
   implicit none
   class(base_t), allocatable :: p
   type(ext1_t) :: a1
   
   print '(/,a)','*** do : a1 = ext1_t (1,2) ***'
   a1 = ext1_t (1,2) 
   
   print '(/,a)','***  do : p = a1 ***'
   p = a1 

   print '(/,a)','*** do : a1 = p ***'   
   a1 = p ; print*,'a1 =',a1
   
end program test

It compiles and works well with ifort, producing the obvious outputs:

*** do : a1 = ext1_t (1,2) ***

 --> ext1EqCl

 

***  do : p = a1 ***

 --> generic_assign

 

*** do : a1 = p ***

 --> ext1EqCl

 a1 =           1           2

 

But it doesn't compile with gfortran, producing the error: Ambiguous interfaces in intrinsic assignment operator for « generic_assign » at (1) and « ext1eqcl » at (2).

If I remove the generic assignment from ext1 and I add the procedure ext1EqCl in the assignment interface as in the following version of typedefs module:

module typedefs
   implicit none
   
   type base_t
      integer :: i = 0
   end type base_t
   
   type, extends(base_t) :: ext1_t
      integer :: j = 0
   end type ext1_t
      
   interface assignment(=)
      module procedure generic_assign
      module procedure ext1EqCl
   end interface

contains     
    
   subroutine generic_assign (lhs, rhs)
      class(base_t), intent(in )              :: rhs
      class(base_t), intent(out), allocatable :: lhs
      print*,'--> generic_assign'
      allocate (lhs, source=rhs)
   end subroutine generic_assign

   subroutine ext1EqCl (lhs, rhs)
      class(base_t), intent(in ) :: rhs
      type (ext1_t), intent(out) :: lhs
      print*,'--> ext1EqCl'
      select type(rhs)
         type is (ext1_t)
            lhs%i = rhs%i ; lhs%j = rhs%j
      end select      
   end subroutine ext1EqCl
   
end module typedefs

it compiles and works well with gfortran but not with ifort ( error #6745: The type/rank signature for the arguments of this specific subroutine matches another specific subroutine that shares the same defined ASSIGNMENT.   [EXT1EQCL]).

Thank you very much for your time.

ps: ifort --version:  ifort (IFORT) 15.0.3 20150408     gfortran --version: GNU Fortran (GCC) 6.3.0

 

 

 

0 Kudos
7 Replies
Steve_Lionel
Honored Contributor III
514 Views

You're using an old compiler and trying to use a Fortran 2008 feature that version did not support. It works in the upcoming ifort 18, in beta now. (Polymorphic assignment isn't supported in version 17.)

D:\Projects>ifort t.f90
Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, 
Version 18.0.0.065 Beta Build 20170320
Copyright (C) 1985-2017 Intel Corporation.  All rights reserved.

ifort: NOTE: The Beta evaluation period for this product ends on 12-oct-2017 UTC.
Microsoft (R) Incremental Linker Version 14.10.25019.0
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:t.exe
-subsystem:console
t.obj

D:\Projects>t.exe

*** do : a1 = ext1_t (1,2) ***
 --> ext1EqCl

***  do : p = a1 ***
 --> generic_assign

*** do : a1 = p ***
 --> ext1EqCl
 a1 =           1           2

 

0 Kudos
riad_h_1
Beginner
514 Views

Thanks Steve. Does it mean that for instructions  like p = a1 and a1 = p user defined assignments are no more needed with ifort 18 ?

Best

0 Kudos
FortranFan
Honored Contributor II
514 Views

Steve Lionel (Ret.) wrote:

You're using an old compiler and trying to use a Fortran 2008 feature that version did not support. It works in the upcoming ifort 18, in beta now. (Polymorphic assignment isn't supported in version 17.)  ..

Steve,

OP is doing defined assignments and therefore, the feature of polymorphic types in intrinsic assignments supported since Fortran 2008 should not matter.

OP presents 2 cases in the original post and says the first works with the older Intel Fortran compiler but gets an error with the second case; please note the behavior is similar with the latest version, 18 beta update 1.  Case 1 works but case 2 leads to "error #5286: Ambiguous generic interface ASSIGNMENT(=): previously declared specific procedure GENERIC_ASSIGN is not distinguishable from this declaration. [EXT1EQCL]" instead of error#6745 with compiler 15.  At first glance though, this appears alright to me, case 1 is acceptable but case 2 does involve an ambiguous interface.

0 Kudos
FortranFan
Honored Contributor II
514 Views

riad h. wrote:

Thanks Steve. Does it mean that for instructions  like p = a1 and a1 = p user defined assignments are no more needed with ifort 18 ?

Best

@riad h.,

With your "a1 = p" assignment on line 54 in case 1 of the original post, you will still require a defined assignment.

0 Kudos
Steve_Lionel
Honored Contributor III
514 Views

Sigh - this is what I get for reading too fast.

I'm not comfortable with ifort's allowing the first case. I think it is just as ambiguous as the second case. The standard says:

Within the scope of the generic ASSIGNMENT (=) identifier, if two procedures have that identifier, one shall have a dummy argument that corresponds by position in the argument list to a dummy argument of the other that is distinguishable from it.

class(base_t) and class(ext1_t) are not distinguishable because an actual argument of type(ext1_t) matches both. Really, the two cases are the same - it's just a different way of creating the generic. Please submit this to Intel Support.

0 Kudos
riad_h_1
Beginner
514 Views

Thanks Steve and FortranFan. Yes Steve, I agree with you and that was I fought when I wrote these two versions. 

With F2003, the generic interface(=) is required for the case where the lhs is polymorphic.
So, if I understand (and unless I use ifort 18 which allow polymorphic lhs), I can not handle assignment operations where both lhs and rhs can be either polymorphics.

At first glance I thought that it was possible, may be I misinterpreted a sentence like "There is the restriction that the variable on the left of an intrinsic assignment statement must not be polymorphic" (The Fortran 2003 Handbook, Adams et al.) which gives the impression that the opposite is allowed.

Sincerely yours

 

0 Kudos
Steve_Lionel
Honored Contributor III
514 Views

This is a change between F2003 and F2008. I don't know what the "Fortran 2003 Handbook" said.

0 Kudos
Reply