- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If gfortran allows this, it is a bug. As an associate name, tt does not have the ALLOCATABLE attribute. The standard says (F2018 11.1.3.3) "The associating entity does not have the ALLOCATABLE or POINTER attributes; it has the TARGET attribute if and only if the selector is a variable and has either the TARGET or POINTER attribute." And 11.1.3.2 says "If and only if the selector is polymorphic, the associating entity is polymorphic."
For intrinsic assignment, 10.2.1.2 says "if the variable is polymorphic it shall be allocatable and not a coarray,"
Therefore, tt is polymorphic, is not allocatable, and intrinsic assignment is undefined.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for your comments.
Fortran2008 or Fortran2018?
So, under your opinion, the procedure that I have done for ifort zone is also correct?
If yes, then gfortran have another bug because give me an error about polymorphic assignation.
Thanks
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I quoted Fortran 2018 but the same holds for Fortran 2008 (just the references will be different.)
I can't spot a problem with your ifort section.
tmp is class(refl_type) and allocatable, and List%reflections(i) is also class(refl_type), so intrinsic assignment is fine. What did gfortran give as an error message? (A request - when writing that a compiler didn't like something, show us the exact and complete text of the error message! Also be clear about which exact compiler version you used. Showing console output, including the compile command, is preferable.)
It may simply be that the version of gfortran you're using doesn't yet support polymorphic assignment. That's a F2008 feature and ifort didn't support it until fairly recently. gfortran isn't close to F2008 yet (I don't think the full F2003 version is released yet.)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello,
The error message is:
List%reflections(i)=List%reflections(j)
Error: Nonallocatable variable must not be polymorphic in intrinsic assignment at (1) - check that there is a matching specific subroutine for '=' operator.
I have checked it on gfortran 8.1 in Windows and gfortran 9.1 in MacOS obtaining the same problem.
Thanks for all.
Javier
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hmm - now that I look at it again, gfortran is correct. While List%reflections is allocatable and polymorphic, List%reflections(i) is not. I now recall we've had some discussions on this before and the wording is clear that a subobject of an allocatable isn't itself an allocatable. Otherwise, it would be possible for different elements to be of different type! So this is an ifort bug.
If you enclose this code in a SELECT TYPE construct, it should work - except that I get an internal compiler error when I try it! I will report both of these bugs. (Ticket numbers are 04248892 and 04248904.)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
OK
But in this case, I'm looking for a good alternative.
Could you suggest me an appropriate form to do this?
Thanks in advance.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Javier Gonzalez-platas wrote:OK
But in this case, I'm looking for a good alternative.
Could you suggest me an appropriate form to do this?
Thanks in advance.
You may want to consider the "defined assignment" option in the Fortran standard if you really have a need to work with a polymorphic component of 'Reflections' in your 'RefList_Type' derived type. However you may take note avoiding polymorphism, if that's an option for you, can make matters simpler for you and also help you with performance.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This seems to work:
class(Refl_Type), allocatable :: tmp1,tmp2 !> IFort select type(ref => List%reflections) type is (refl_type) tmp1=ref(i) tmp2 = ref(j) ref(j)=tmp1 ref(i)=tmp2 class default error stop "Wrong type!" end select
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
OK
In order to be more general, as list%reflections have to be the same type I could use class is (refl_type), right?
Javier
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You could use CLASS IS here [edit: no], but it has a subtly different meaning. Here's how the standard describes it:
"A TYPE IS type guard statement matches the selector if the dynamic type and kind type parameter values of the selector are the same as those specified by the statement. A CLASS IS type guard statement matches the selector if the dynamic type of the selector is an extension of the type specified by the statement and the kind type parameter values specified by the statement are the same as the corresponding type parameter values of the dynamic type of the selector."
CLASS IS would probably work here too [edit: nope - see below], and would allow List%reflections to be an extension of Refl_type.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve Lionel (Ret.) (Blackbelt) wrote:You could use CLASS IS here ..
..
CLASS IS would probably work here too, and would allow List%reflections to be an extension of Refl_type.
I don't think "CLASS IS" will work. I think it will place OP back to square one: within "CLASS IS: branch of "select type ( ref => List%reflections )", the standard - if I'm not mistaken - stipulates the associating-entity "ref" be polymorphic similar to ASSOCIATE in OP's original post and will thus disallow intrinsic assignments such as "ref(j)=tmp1"
OP with statements such as "In order to be more general, as list%reflections have to be the same type I could use class is (refl_type)" appears to seek certain coding brevity. If that's the case and the polymorphism of the type component of "Reflections" is important, my hunch is OP will need to make some compromise somewhere and add more code.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
FF is correct, CLASS IS would NOT work here as stated.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dear all,
I don't understand why something as simple a swap between 2 polymorphic components as in this case
list%reflections(i)=list%reflections(j)
is giving so much problems.
As resume, if I want to have a general procedure working in different compilers, the only thing that I see is do a swap (or copy) element by element according with the type. For me (I'm not expert) it is inconceivable.
Thanks for all
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
To finish...
Here the code for a simplified example (take the general idea about extends types and so on...). Seems that uses polymorphic variables is more complicate than I expected.
Thanks.
Program Check
implicit none
!> Type definitions
Type :: Refl_Type
integer,dimension(:), allocatable :: H
integer :: Mult =0
End Type Refl_Type
Type, extends (Refl_type) :: sRefl_Type
integer :: S =0
End Type sRefl_Type
Type, extends (sRefl_type) :: tRefl_Type
integer :: T =0
End Type tRefl_Type
Type :: RefList_Type
integer :: Nref
class(refl_Type), dimension(:), allocatable :: Reflections
end Type RefList_Type
Type(RefList_Type) :: List
Type(Refl_Type), dimension(3) :: Refl_Ini
!> Variables
integer :: i
!> Init
Refl_Ini(1)%H=[1, 0, 0]; Refl_Ini(1)%Mult=1
Refl_Ini(2)%H=[0, 2, 0]; Refl_Ini(2)%Mult=2
Refl_Ini(3)%H=[0, 0, 3]; Refl_Ini(3)%Mult=3
List%Nref=3
List%Reflections=Refl_Ini
!> Print Step:1
do i=1, List%Nref
print '(i3,2x,3i4,2x,i3)', i,List%Reflections(i)%H, List%Reflections(i)%Mult
end do
print*,' '
print*,' '
!> Swap
call Swap_Elements_List(List, 1, 3)
!> Print Step:2
do i=1, List%Nref
print '(i3,2x,3i4,2x,i3)', i,List%Reflections(i)%H, List%Reflections(i)%Mult
end do
Contains
Subroutine Swap_Elements_List(List, i, j)
!---- Argument ----!
type (RefList_Type), intent(in out) :: List
integer, intent(in) :: i,j
!---- Local Variables ----!
class(Refl_Type), allocatable :: tmp, tmp1,tmp2
!> IFort 19
!tmp=List%reflections(i)
!List%reflections(i)=List%reflections(j)
!List%reflections(j)=tmp
!> Gfortran
!associate(t1 => list%reflections(i), t2 => list%reflections(j), tt => tmp)
! tt=t1
! t1=t2
! t2=tt
!end associate
!> General
tmp1=List%reflections(i)
tmp2=List%reflections(j)
select type (ref => List%Reflections)
type is (refl_type)
ref(i)%h=tmp2%h
ref(i)%Mult=tmp2%Mult
ref(j)%h=tmp1%h
ref(j)%Mult=tmp1%Mult
type is (sRefl_type)
ref(i)%h=tmp2%h
ref(i)%Mult=tmp2%Mult
ref(j)%h=tmp1%h
ref(j)%Mult=tmp1%Mult
select type (tmp2)
type is (srefl_type)
ref(i)%S=tmp2%S
end select
select type (tmp1)
type is (srefl_type)
ref(j)%S=tmp1%S
end select
type is (tRefl_type)
ref(i)%h=tmp2%h
ref(i)%Mult=tmp2%Mult
ref(j)%h=tmp1%h
ref(j)%Mult=tmp1%Mult
select type (tmp2)
type is (srefl_type)
ref(i)%S=tmp2%S
type is (trefl_type)
ref(i)%S=tmp2%S
ref(i)%T=tmp2%T
end select
select type (tmp1)
type is (srefl_type)
ref(j)%S=tmp1%S
type is (trefl_type)
ref(j)%S=tmp1%S
ref(j)%T=tmp1%T
end select
end select
End Subroutine Swap_Elements_List
End Program Check
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The problem is that when you have a polymorphic variable, it can change types. That's the whole idea of polymorphism. When you do an assignment to a polymorphic variable, it assumes the dynamic type of what is being assigned to it, and that requires it to be allocatable.
But more of a problem is that you don't want to assign the whole variable, which is easier, you want to assign individual elements, and these are not allocatable. So you need to tell the compiler which type you're assigning with SELECT TYPE.
I have not looked at your newest code yet.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Javier Gonzalez-platas wrote:.. I don't understand why something as simple a swap between 2 polymorphic components as in this case
list%reflections(i)=list%reflections(j)
is giving so much problems.
As resume, if I want to have a general procedure working in different compilers, the only thing that I see is do a swap (or copy) element by element according with the type. For me (I'm not expert) it is inconceivable. ..
Fortran has considerable limitations when it comes to generics: a 'generic' swap routine in Fortran with the current standard will end up requiring a lot of code by the user in form or other to ensure it covers all anticipated scenarios as OP has discovered with the latest revision in Quote #15.
The issue with generics with intrinsic types as well as derived types, just that with polymorphism there is added complexity and checks can even get deferred to run-time, as opposed to compile-time, and this can lead to more problems.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The internal compiler error is fixed in compiler 19.1. The lack of an error message in the erroneous case is not yet fixed.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The lack of an error message will be fixed in the 2021.6 compiler release - so Intel tells me.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page