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.
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
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)