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

Error extending extended types

Diarmaid_d_
Beginner
399 Views
I am trying to use the object orientated features of Fortran (Essentially, what I want to be able to do is to get an array of arraies, where each element of the outer array has a different size), and I have run into the following error,Is this a bug?>
Undefined symbols for architecture x86_64:

  "_valout_", referenced from:
      _TBPLIST_PACK_3.0.1 in ifortgrMMR7.o
ld: symbol(s) not found for architecture x86_640

I know that I have defined ValOut, and this appears to be a bug with the compiler when you extend an extended type which has allocatable components inside.

I have attached below the code to show this, together with the compilation command.   I am using ifort version 17.0.2.   I have tested it against ifort version 17.0.2 and ifort version 16.0.0, both of which give the same error.   However, when I tested it with gfortran (gcc version  6.1.0) it worked.

What the code is is an abstract type (a Feature) which has a deferred procedure (ValOut).   This takes as input the class (Feature) and a set of real values (vauesOut).   

module FeatureMod
  use iso_fortran_env

  type, abstract:: feature
      character(len=:), allocatable:: name
    contains
      procedure (ValOut), deferred :: getAllValues
  end type

  interface 
    subroutine ValOut(self, valuesOut)
      use iso_fortran_env
      import Feature
    class(Feature), intent(in):: self
      real(real64), dimension(:):: valuesOut
    end subroutine ValOut

  end interface 

contains

end module FeatureMod

I now define an extension of the type Feature where I override ValOut. For this extension, I set ValOut to be 1.

module FirstFeatureMod
use iso_fortran_env
use FeatureMod
implicit none

   type, extends(feature):: secondType
     real, dimension(:), allocatable::r
     contains
       procedure:: getAllValues => getAllValuesSecond
   end type secondType

   contains

     subroutine getAllValuesSecond(self, valuesOut)
       class(secondType), intent(in):: self
       real(real64), dimension(:):: valuesOut

       valuesOut = 1
    end subroutine
end module FirstFeatureMod

I also define a thirdType (extending second type), and a fifthType(extending secondType).   For these functions, I override ValOut to set the output to be 3 and 5 respectively.

module SecondFeatureMod
  use FirstFeatureMod

  type, extends(secondType):: thirdType
    integer:: k=6
  contains
    procedure:: getAllValues => getAllValuesThird
  end type thirdType

  type, extends(secondType):: fifthType
    integer:: l=22
    contains
    procedure:: getAllValues => getAllValuesFifth
    end type

  contains
     subroutine getAllValuesThird(self, valuesOut)
       class(thirdType), intent(in):: self
       real(real64), dimension(:):: valuesOut

       valuesOut = 3
    end subroutine
     subroutine getAllValuesFifth(self, valuesOut)
       class(fifthType), intent(in):: self
       real(real64), dimension(:):: valuesOut

       valuesOut = 5
    end subroutine
end module SecondFeatureMod

Because I want an array of these, I define class which holds a pointer to a Feature class.   This allows me to get an array of these arrays by defining ar array of the type holding the pointer.

module ListFeatureMod
  use FeatureMod
  use FirstFeatureMod

  

  type:: checkType
    class(feature), pointer:: l
    contains
      procedure:: setType
  end type

  type:: listOfCheck
    type(checkType), dimension(:), allocatable:: list
  contains
    procedure, pass:: allocateTypes
  end type

contains
  subroutine allocateTypes(self, intIn)
    class(listOfCheck), intent(inout):: self
    integer, intent(in):: intIn

    allocate(self%list(intIn))

  end subroutine allocateTypes

  subroutine setType(self, typeIn)
  class(checkType), intent(inout):: self
  class(feature), intent(in):: typeIn

    allocate(self%l, source=typeIn)
  end subroutine setType

end module 

Finally, I wrote a short program to test this, where I define an array of length 3, I set each element of the array to be a different derived type, and I write out the results.    The expected results are simply 3,3,3\n1,1,1\n5,5,5.

program test

  use FeatureMod
  use FirstFeatureMod
  use SecondFeatureMod
  use ListFeatureMod
  integer:: N, i

  type(thirdType), target:: b
  type(secondType), target:: c
  type(fifthType), target:: e
  type(listOfCheck):: k
  real(real64), dimension(3)::r


  call k%allocateTypes(3)


  call k%list(1)%setType(b)
  call k%list(2)%setType(c)
  call k%list(3)%setType(e)

  do i = 1, 3
    call k%list(i)%l%getAllValues(r)
    write(*,*) r
  end do

contains

end program

But this doesn't compile.   I am trying to compile with no special flags 

ifort Feature.f90 FirstFeature.f90 SecondFeature.f90 ListFeature.f90 FeatureContainer.f90 

 

Is this a bug?   Does Fortran allow me to do what I want to do?   If not, is there another way to get this to work?

This bug doesn't appear if none of the types have allocatable components, so it might be possible to get around it by using something like

type, abstract:: feature(length)
integer, len:: length
contains
.
.
end type

type, extends(feature):: secondFeature
   real(real64), dimension(lenght):: values
  contains
    .
    .
    .
end type

But I have had some serious issues trying to get the integer, len:: features of ifort to work.

Any help would be much appreciated.

0 Kudos
3 Replies
FortranFan
Honored Contributor II
399 Views

Hopefully you can get Intel staff to chime in along with other experts on Fortran, but I think as you have coded, it gets into one of those gray areas as far as the Fortran standard is concerned and things may be left up to the processor to decide.  And what I mean by this is as follows: your deferred procedure getAllValues is indicated to have the explicit interface ValOut as opposed to an ABSTRACT interface; the linker used with Intel Fortran seems to think there is an external procedure corresponding to this interface and is raising an error when it cannot find it.  I'll hold my comments on whether this is legit and leave it up to Intel support and others to comment.

But in the meantime, you can avoid the error by applying the ABSTRACT attribute on the ValOut interface which may be what you had in mind in the first place:

   abstract interface
      subroutine ValOut(self, valuesOut)
         import :: Feature, real64
         implicit none
         class(Feature), intent(in):: self
         real(real64), dimension(:):: valuesOut
      end subroutine ValOut
   end interface

 

0 Kudos
Diarmaid_d_
Beginner
399 Views

Changing it to ABSTRACT INTERFACE fixed my problem, thanks!

0 Kudos
Kevin_D_Intel
Employee
399 Views

Thank you for complete description of your issue and test case. I confirmed the findings with ifort and gfortran and submitted this to our Developers for their analysis. Both compilers use the same underlying linker so it appears ifort may not be handling this unique case properly. Our Developers are better suited to comment about the conformance of the code to the Fortran Standard so I'll lean on their expertise about that.

Thank you very much FortranFan for your expert comments and advice. Your contributions are always greatly appreciated.

(Internal tracking id: CMPLRS-43176)

0 Kudos
Reply