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

Trouble with polymorphic entities

Christopher_W_1
Beginner
846 Views

Hello,

I am experiencing several error messages about polymorphic entities with ifort 14.0.1 (Linux) which I find strange.However, I am relatively new to OO Fortran features, so I am not sure if this is a compiler or a personal problem ;-)

Could anyone of you be so kind and have a look at the following sample code?

     MODULE shapes

      ! A general shape
      TYPE, ABSTRACT :: shape
      CHARACTER :: color *8 = 'black'
      CONTAINS
      PROCEDURE :: list   => shape_list
      END TYPE shape

      ! A specialized shape : a sphere
      TYPE, EXTENDS(shape) :: sphere
      REAL :: radius = 1.0
      CONTAINS
      PROCEDURE :: list   => sphere_list
      END TYPE sphere


      CONTAINS


      SUBROUTINE shape_list(this)
      CLASS(shape), INTENT(IN) :: this
      print '(A6, " = ",A8)', "COLOR", this % color
      END SUBROUTINE

      SUBROUTINE sphere_list(this)
      CLASS(sphere), INTENT(IN) :: this
      CALL this % shape % list                !  <---------------------   error
      print '(A6, " = ",F6.3)', "RADIUS", this % radius
      END SUBROUTINE

      END MODULE


ifort gives me the following error on this:

sample01.f(28): error #8307: If the rightmost part-name is of abstract type, data-ref shall be polymorphic   [SHAPE]
      CALL this % shape % list      !  <---------------------   error
------------------^
sample01.f(28): error #8318: If the component immediately preceding the type-bound procedure is abstract, the entire data reference before the procedure name must be polymorphic.   [SHAPE]
      CALL this % shape % list      !  <---------------------   error

Why is "this" not a polymorphic entity?

Why am I not allowed to call the list method of the (abstract) base class? Since "this" is a real object, everything should be well-defined.

My workaround is to rename the list method of shape to list_base, or to call shape_list directly.

What I actually want to do is to call the list method of the parent class (something like super::list() in C++).
Is there any way to do this in Fortran without mentioning shape explicitely, so I could add a class "round_shape"
between shape and sphere at some later time without having to rename the in list() ?



 ---------------------



Second, I am confused when I am allowed to pass derived types as dummy arguments and when not.

If I add a field currentShape and a subroutine SAVE_ANY_SHAPE to my shape module (*not* to a specific type):

 
      CLASS(shape), POINTER :: currentShape

      ... CONTAINS ...

      SUBROUTINE SAVE_ANY_SHAPE(a_shape)
      CLASS(shape), POINTER, INTENT(IN) :: a_shape
      currentShape => this
      END SUBROUTINE

and have the following main program:

      PROGRAM test
      
      USE shapes
      CLASS(shape),  POINTER :: pshape
      CLASS(sphere), POINTER :: psphere

      ALLOCATE(psphere)
      CALL SAVE_ANY_SHAPE(psphere)  <------------------   error

      END PROGRAM test

I get a compile-time "error #6633: The type of the actual argument differs", but

      ALLOCATE(psphere)
      pshape => psphere
      CALL SAVE_ANY_SHAPE(pshape)

works. Also, if I remove the POINTER attribute and add a TARGET attribute to a_shape, I can call SAVE_ANY_SHAPE with either of pshape and psphere as argument without error. Is this really how it should be? Why are targets polymorphic and pointers not?


Thank you for your hints!

   Christopher

0 Kudos
2 Replies
reinhold-bader
New Contributor II
846 Views

Hello,

with respect to your first question: "this" is a polymorphic entity, but "this%shape", being a reference to the abstract parent type, is not. Disallowing an object to be of abstract dynamic type is a fundamental property of the concept, by the way. From the point of view of re-using your template method in overrides, you could replace

CALL this % shape % list   

by

CALL shape_list(this)

As far as your second question is concerned: If a polymorphic dummy argument has the POINTER or ALLOCATABLE attribute, the actual argument is required to have the same declared type as the dummy. The reason for this is that the type compatibility rules must be applied in two ways: First, the incoming object must be either of the same type or an extension of that of the dummy. Second, an allocation or pointer assignment inside the procedure may cause the dynamic type of the object to become, at worst, the declared type of the dummy. Hence, on return from the procedure you'd get an inconsistency if the actual argument were of an extension type of the declared type of the dummy.

(Note that the pointer assignment inside your SAVE_ANY_SHAPE is to an undeclared entity "this"; presumably it should be to "a_shape"?

Regards

Reinhold

 

0 Kudos
Izaak_Beekman
New Contributor II
846 Views

I will also note that it's a bit odd to declare a non-deferred type bound procedure and data components in an abstract type in this context. Typically, the point of an abstract type is to define the methods which the concrete type should implement, and their interfaces. It is an interface specification/contract tool. Sure, it can have default data elements, and perhaps some non-override-able default methods, but it must have a concrete implementation to be used. (You can only use these methods and data components from a concrete type which extends it.)

You could simply remove 'abstract' from the type declaration and I think it would work. Also, if you don't overload list, i.e. keep distinct names you could CALL this%shape_list which sphere inherits from shape.

0 Kudos
Reply