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

select type bug ??

Patrice_l_
Beginner
1,344 Views

Hi all,

I put a small example together to show a behavior i don't understand, hoping for some explanation here. 

This code end up with the following in intel 15 version, the copy is not made despite the select type.  Also Is the extends_type_of results correct ?

Thanks.

class cm2 is type tm T
 class cm2 is class cm T
 class cm2 is type tc T
 class cm2 is class cc T
 cm2=cm          10           1

With gfortran 4.9.1 I have :

class cm2 is type tm T
 class cm2 is class cm T
 class cm2 is type tc F
 class cm2 is class cc T
 cm2=cm          10           1

 

program toto
implicit none

type mother
integer :: i
end type mother
type,extends(mother) :: child
end type child

type(mother) :: tm
type(child) :: tc
class(mother),allocatable :: cm,cm2
class(child),allocatable :: cc

 allocate(cm)
 allocate(child::cm2)
 cm%i=10
 cm2%i=1
 select type (cm2)
 type is (mother)
                cm2=cm
 end select
 print *,'class cm2 is type tm',extends_type_of(cm2,tm)
 print *,'class cm2 is class cm',extends_type_of(cm2,cm)
 print *,'class cm2 is type tc',extends_type_of(cm2,tc)
 print *,'class cm2 is class cc',extends_type_of(cm2,cc)
 print *,'cm2=cm', cm%i,cm2%i
 
end program

 

0 Kudos
23 Replies
FortranFan
Honored Contributor III
1,232 Views

I think gfortran 4.9.1 gives the correct response for both aspects of your code: the SELECT TYPE construct as well as the EXTENDS_TYPE_OF inquiry function whereas Intel Fortran only seems to work for the first aspect.  Shouldn't the copy only take place with [fortran]CLASS IS (mother)[/fortran] construct since cm2 is a polymorphic object?

 

0 Kudos
Patrice_l_
Beginner
1,232 Views

 

You are right, the type is (mother) is false in the select construct, but true in extends_type_of for both compiler.

In my understanding, cm2 is polymorphic with dynamic type of child because of the allocate, but the select construct should allow

to do a copy of the mother attributes. Also selecting class is (mother) , doesn' t suits me, because polymorphic assignment is not supported yet.

0 Kudos
FortranFan
Honored Contributor III
1,232 Views

Patrice l. wrote:

 

You are right, the type is (mother) is false in the select construct, but true in extends_type_of for both compiler.

In my understanding, cm2 is polymorphic with dynamic type of child because of the allocate, but the select construct should allow

to do a copy of the mother attributes. Also selecting class is (mother) , doesn' t suits me, because polymorphic assignment is not supported yet.

I think your best bet would be defined assignment.

My understanding is TYPE IS case in the SELECT TYPE construct only works when the dynamic type matches exactly with the case specification which is not true in your case.

Also, when polymorphic assignment may also not work out for you whenever it becomes available: isn't it simply "syntactic sugar" i.e., short-form for 

[fortran]

IF (ALLOCATED(lhs)) THEN  !.. This may take place when lhs and rhs are not the same exact type

   DEALLOCATE(lhs)

END IF

ALLOCATE(lhs, SOURCE=rhs))

[/fortran]

so the dynamic type of cm2 may change to mother following the assignment which may not be your desired result. 

0 Kudos
Steven_L_Intel1
Employee
1,232 Views

I think the Intel results are correct. TYPE IS is not the same as EXTENDS_TYPE_OF. The SELECT TYPE should not be done because the dynamic type of cm2 is child and not mother. But EXTENDS_TYPE_IS would return true because cm2 and tc are the same dynamic type (child) and the standard says "extension type (of one type with respect to another) is the same type or is an extended type whose parent type is an extension type of the other type." (emphasis mine)

0 Kudos
Patrice_l_
Beginner
1,232 Views

Ok, In this case what is the best way to copy a mother information into a child one, knowing im exteding the type to allow a specific behavior for a function ?

I tried many different combination of cm,cc,tc,tm apart from the cm assignment not supported, I can not perform this copy without writting it explicitly.

Thanks.

0 Kudos
FortranFan
Honored Contributor III
1,232 Views

Patrice l. wrote:

Ok, In this case what is the best way to copy a mother information into a child one, knowing im exteding the type to allow a specific behavior for a function ?

I tried many different combination of cm,cc,tc,tm apart from the cm assignment not supported, I can not perform this copy without writting it explicitly.

Thanks.

As I mentioned in Quote #4, you can consider a defined assignment i.e., including a type-bound procedure in the base class that is tied to a generic assignment.  

0 Kudos
Patrice_l_
Beginner
1,232 Views

FortranFan wrote:

 

As I mentioned in Quote #4, you can consider a defined assignment i.e., including a type-bound procedure in the base class that is tied to a generic assignment.  

 

And I wrote without writting it explicitly .

0 Kudos
Steven_L_Intel1
Employee
1,232 Views

Perhaps you need to wait for polymorphic assignment (a F2008 feature) to be supported.

0 Kudos
FortranFan
Honored Contributor III
1,232 Views

Steve Lionel (Intel) wrote:

.. the standard says "extension type (of one type with respect to another) is the same type or is an extended type whose parent type is an extension type of the other type." (emphasis mine)

Thanks, I missed that part.

0 Kudos
FortranFan
Honored Contributor III
1,232 Views

Steve Lionel (Intel) wrote:

Perhaps you need to wait for polymorphic assignment (a F2008 feature) to be supported.

Steve,

How exactly will polymorphic assignment work when it does get implemented?  Will it not make the left-hand side end up with the same dynamic type as right-hand side?  i.e., for the code example in OP, will not cm2 end up with the dynamic type of cm i.e., mother and isn't that something that may not be the desired result, meaning the intent may be for cm2 to retain the type of child.

In other words, can you please comment on the following?

FortranFan wrote:

..

Also, when polymorphic assignment may also not work out for you whenever it becomes available: isn't it simply "syntactic sugar" i.e., short-form for 

[fortran]

IF (ALLOCATED(lhs)) THEN  !.. This may take place when lhs and rhs are not the same exact type

   DEALLOCATE(lhs)
END IF
ALLOCATE(lhs, SOURCE=rhs))

[/fortran]

so the dynamic type of cm2 may change to mother following the assignment which may not be your desired result. 

0 Kudos
Steven_L_Intel1
Employee
1,232 Views

What FortranFan wrote is what the standard says the behavior is, and you can do that today. I had started to suggest that and had, for some reason, convinced myself it wouldn't help.

0 Kudos
Patrice_l_
Beginner
1,232 Views

FortranFan,

In my understanding what might work is , cm2 has dynamic type of child, but in the select type it uses class is mother, then the copy that i want should be performed without modifying the dynamic type. Intrinsic assignment would be the feature in that case.

0 Kudos
Steven_L_Intel1
Employee
1,232 Views

I'm thinking that the assignment would not be allowed. Note that inside the SELECT TYPE, cm2 loses its allocatable attribute (same as with ASSOCIATE) and thus you have a non-allocatable variable of type mother being assigned a value of type child, and that's not valid since they're not the same type.

0 Kudos
FortranFan
Honored Contributor III
1,232 Views

Patrice l. wrote:

FortranFan,

In my understanding what might work is , cm2 has dynamic type of child, but in the select type it uses class is mother, then the copy that i want should be performed without modifying the dynamic type. Intrinsic assignment would be the feature in that case.

Is this something you're looking for?

MODULE m

   !..
   IMPLICIT NONE

   !..
   PRIVATE

   TYPE, PUBLIC :: mother
      !..
      PRIVATE
      INTEGER, PUBLIC :: i

   CONTAINS
      PRIVATE
      PROCEDURE, PASS(this) :: assign_mother
      GENERIC, PUBLIC :: ASSIGNMENT(=) => assign_mother
   END TYPE mother

   TYPE, EXTENDS(mother), PUBLIC :: child
   END TYPE child

CONTAINS

   PURE ELEMENTAL SUBROUTINE assign_mother(this, rhs)

      !.. Argument list
      CLASS(mother), INTENT(INOUT) :: this
      CLASS(*), INTENT(IN)         :: rhs

      !..
      SELECT TYPE (rhs)
         CLASS IS (mother)
            this%i = rhs%i
         TYPE IS (INTEGER)
            this%i = rhs
         CLASS DEFAULT
            !.. Insert error handling here
      END SELECT

   END SUBROUTINE assign_mother

END MODULE m

PROGRAM p

   USE m, ONLY : mother, child

   !..
   IMPLICIT NONE

   !.. Local variables
   TYPE(mother) :: tm
   TYPE(child) :: tc
   CLASS(mother), ALLOCATABLE :: cm
   CLASS(mother), ALLOCATABLE :: cm2
   CLASS(child), ALLOCATABLE :: cc

   !..
   ALLOCATE(cm)
   ALLOCATE(child::cm2)
   SELECT TYPE (cm2)
      TYPE IS (mother)
         PRINT *, "cm2 is of type mother following allocation."
      TYPE IS (child)
         PRINT *, "cm2 is of type child following allocation."
      CLASS DEFAULT
         PRINT *, "cm2 is of type other than mother or child following allocation."
   END SELECT

   ALLOCATE(cc)

   cm%i=10
   !.. 
   cm2 = 1
   PRINT *, "cm2 = ", cm2%i, " following initialization."

   !..
   cm2 = cm

   !..
   PRINT *,'class cm2 is type tm',EXTENDS_TYPE_OF(cm2,tm)
   PRINT *,'class cm2 is class cm',EXTENDS_TYPE_OF(cm2,cm)
   PRINT *,'class cm2 is type tc',EXTENDS_TYPE_OF(cm2,tc)
   PRINT *,'class cm2 is class cc',EXTENDS_TYPE_OF(cm2,cc)
   PRINT *,'cm2=cm', cm%i,cm2%i

   SELECT TYPE (cm2)
      TYPE IS (mother)
         PRINT *, "cm2 is of type mother following assignment."
      TYPE IS (child)
         PRINT *, "cm2 remains of type child following assignment."
      CLASS DEFAULT
         PRINT *, "cm2 is of type other than mother or child following allocation."
   END SELECT

   !..
   STOP

END PROGRAM p

The program runs as follows:

 cm2 is of type child following allocation.
 cm2 =  1  following initialization.
 class cm2 is type tm T
 class cm2 is class cm T
 class cm2 is type tc T
 class cm2 is class cc T
 cm2=cm 10 10
 cm2 remains of type child following assignment.
Press any key to continue . . .

 

0 Kudos
Patrice_l_
Beginner
1,232 Views

FortranFan,

The main program looks exactly like what i would like to write, and in practice I wrote a version avoid the select type in the assignment (i already know it). But ultimately It would be nice not to have to right that assignment function.

0 Kudos
Steven_L_Intel1
Employee
1,232 Views

Does this do what you want?

 select type (cm2)
 type is (child)
                cm2%mother=cm
 end select

 

0 Kudos
Patrice_l_
Beginner
1,232 Views

Yes steve,

This is exactly what i was looking for. "But i'm confused now, there is no field mother but that works perfectly in the select type is there a part of the standard i missed ?"  Edit : Found it under type extension, very useful ;) Thank you.

It doesn't work with gfortran but i think it is because of their bug with tm=cm which does not give the right result.

0 Kudos
FortranFan
Honored Contributor III
1,232 Views

Steve Lionel (Intel) wrote:

Perhaps you need to wait for polymorphic assignment (a F2008 feature) to be supported.

Steve,

Fyi, the article titled, "Compiler support for the Fortran 2003 and 2008 standards revision 15" by Ian Chivers, Jane Sleightholme at ACM SIGPLAN Fortran Forum, Volume 33 Issue 2, August 2014 indicates Intel Fortran supports the polymorphic assignment feature of Fortran 2008.  Do you think Intel would like to get this misinformation corrected?

Thanks,

0 Kudos
FortranFan
Honored Contributor III
1,232 Views

Patrice l. wrote:

FortranFan,

The main program looks exactly like what i would like to write, and in practice I wrote a version avoid the select type in the assignment (i already know it). But ultimately It would be nice not to have to right that assignment function.

Patrice I.,

Out of curiosity, will it be possible to share on this forum how you resolved the code design for yourself that didn't utilize SELECT TYPE construct?  And also, how is avoiding the SELECT TYPE important?

In addition, why do you think it will be nice not to have to include an assignment in your class design (aka mother type)?  Isn't that the basic premise of object-oriented design, to encapsulate actions on the class side so the consuming code achieves greater clarity and simplicity?  Having a code section in your main program like the snippet by Steve in Quote #17 seems counter to conventional wisdom on OOP.

0 Kudos
Patrice_l_
Beginner
1,148 Views

 

I use the polymorphism by calling the assignment function for class mother , with an argument of class child for left hand side.

Avoiding select type i guess is just a matter of keeping the code simple, especially for nested select type (see other post). Also i feel that select type is just putting a lot of "if" for something that can be resolve at compile time.

Yes encapsulation is beautiful; For specific copy or assignment , for example two sister class which inheritate from the same mother but different extension, one might want a special assignment. But for direct heritage , where the base type can be directly copy, the memory structure is the same the assignment function should be clear enough for the language to figure this out (especially when its a shadow extension (without additional field)). Which the code cm2%mother=cm does perfectly aside from the select type. There is only one straightforward way to copy a mother into a child, copy all of the mother field into the heritated field . and extended field blank. If one want to do more, then I agree , an assignment subroutine is needed.

My feeling is that having to write an assignment subroutine for a type, is like asking me to write "assembly code" to do real a =real b. :)

 

 

subroutine convert_to_child (this,cthis)
        class(mother),intent(in) :: this
        class(child),allocatable :: cthis
      
         if(.not.allocated(cthis)) allocate(child::cthis)
        
        ! assignment function for mother
        call copy_structc(cthis,this) 
        
end subroutine convert_to_child

 

0 Kudos
Reply