automatic array valued function in abstract interface

automatic array valued function in abstract interface

Hello again!

The following abstract derived-type with ABSTRACT INTERFACE causes us (me and the the Intel compiler) some trouble again.
 

It is about a DEFERRED FUNCTION 'make_array' with an automatic array as return value. The shape of the automatic array is obtained from a call to an other DEFERRED FUNCTION 'get_length'. Since I am not super experienced in Fortran, I am not sure if that is standard-comforming (having function calls as dimension declarator for automatic arrays). However, the compiler wasn't much of help to me this time: It just stopped with a segmentation violation (and kindly asked me to report this). So here it is:


module m
    implicit none
 
    type, abstract :: abstract_type
        integer :: length
    contains
        procedure(get_length_interf), deferred :: get_length
        procedure(make_array_interf), deferred :: make_array
    end type
 
    abstract interface
 
       ! returns a dynamic array length
        pure function get_length_interf(this)
            import abstract_type
            implicit none
 
            class(abstract_type), intent(in) :: this
            integer :: get_length_interf
 
        end function
 
        ! returns automatic array,
        ! array length is determined by a call to get_length()
        function make_array_interf(this)
            import abstract_type
            implicit none
 
            class(abstract_type), intent(in) :: this
            integer :: length
            integer, dimension( this%get_length() ) :: make_array_interf     ! CRASH
 
            ! **Internal compiler error: segmentation violation signal raised**
            ! however, dimension( get_length_interf(this) ) works fine.
 
        end function
 
    end interface
end module

Best regards, and thanks for any helpful advice

Ferdinand

7 posts / novo 0
Último post
Para obter mais informações sobre otimizações de compiladores, consulte Aviso sobre otimizações.

I believe that the use of a type-bound procedure should work here. I have escalated this to the developers as DPD200241137. While you are correct that substituting the "direct" call to the function allows it to compile, I find that I can't turn this into anything usable as if I extend the type and supply the overriding function with a dimension based on the other overriddn type-bound function, the compiler complains that the shapes of the function results aren't the same. I think this too is incorrect and have asked the developers to fix that.

I will let you know of any progress on this matter.  Thanks for the nice example.

Steve - Intel Developer Support

Thank you for your quick and informative answer again, Steve!

I also didn't find a simple and elegant workaround yet. In my case, the question is:

How to return private array data (from an abstract derived type), having dimension given in an other private type-bound variable? As Fortran doesn't provide the protected attribute (for derived-type components), the only way I found to achieve this is a public get-function as in the example. An other approach, using allocatable arrays, turned out to be much slower over the use of automatic arrays (is this generally true?).

I think you will have better luck here with allocatable arrays. Yes, this would be slower if the routine didn't do much work and was called a lot, but it is more likely to work correctly. Array-valued functions where the array size depends on a dummy argument have long been a source of problems.

Steve - Intel Developer Support

Hi,

I stumbled about the same problem as I wanted to make use of such a function in my class hierarchy and can make three comments on this:

1) From my current understanding of the Fortran2003/2008 standard the desired behaviour (unfortunately) is not valid. We have the following requirement for overriding tpbs:

The overriding and overridden type-bound procedures shall satisfy the following conditions:

  • ...
  • Either both shall be subroutines or both shall be functions having the same result characteristics (12.3.3).
  • ...

where a part of the result characteristics appears to be that

If a function result is an array that is not allocatable or a pointer, its shape is a characteristic.

The shape is given by the array's rank plus its extents in the individual dimensions. That rules out use of a specification function which returns a different value for each child class and likely even a function returning a value unknown at compile time (but see commen 3 below).

2) In ifort version 14.0.1 the problem of the internal compiler error appears to be fixed. When I try to compile the above code I get the following error message:

error #8497: Illegal use of a procedure name in an expression, possibly a function call missing parenthesis.   [GET_LENGTH]
            integer, dimension( this%get_length() ) :: make_array_interf
-------------------------------------^
compilation aborted for Issue-368481.f90 (code 1)

Compiling a slightly different example (given below) I get a more expressive error message:

example.f90(15): error #8280: An overriding binding and its corresponding overridden binding must both be either subroutines or functions with the same result type, kind, and shape.   [GET_ARRAY]
     procedure :: get_array => get_array_son
------------------^
example.f90(21): error #8280: An overriding binding and its corresponding overridden binding must both be either subroutines or functions with the same result type, kind, and shape.   [GET_ARRAY]
     procedure :: get_array => get_array_daughter
------------------^
compilation aborted for example.f90 (code 1)

module classes
  implicit none
  type, abstract :: base_class

	     integer :: varnum

	   contains

	     procedure(pvf_get_num), nopass, deferred :: get_num

	     procedure(pvf_get_array), pass, deferred :: get_array

	  end type base_class
  type, extends(base_class) :: son_class

	   contains

	     procedure, nopass :: get_num => get_num_son

	     procedure :: get_array => get_array_son

	  end type
  type, extends(base_class) :: daughter_class

	   contains

	     procedure, nopass :: get_num   => get_num_daughter

	     procedure :: get_array => get_array_daughter

	  end type daughter_class
  abstract interface
     pure function pvf_get_num() result(num)

	       integer :: num

	     end function pvf_get_num
     function pvf_get_array( this ) result(array)

	       import base_class

	       class(base_class), intent(in) :: this

	       ! integer, dimension( this%varnum    ) :: array                           

	       integer, dimension( this%get_num() ) :: array

	     end function pvf_get_array
  end interface
contains
  pure function get_num_son() result(num)

	    integer :: num

	    num = 4

	  end function get_num_son

	  pure function get_num_daughter() result(num)

	    integer :: num

	    num = 9

	  end function get_num_daughter
  function get_array_son( this ) result(array)

	    class(son_class), intent(in) :: this

	    ! integer, dimension( this%varnum ) :: array                                

	    integer, dimension( this%get_num() ) :: array

	    array = 0

	    array( this%varnum ) = 1

	  end function get_array_son
  function get_array_daughter( this ) result(array)

	    class(daughter_class), intent(in) :: this

	    ! integer, dimension( this%varnum ) :: array                                

	    integer, dimension( this%get_num() ) :: array

	    array = 0

	    array( this%varnum ) = 2

	  end function get_array_daughter
end module classes

3) When I replace this%get_num()  in the example above by base class component this%varnum ifort (both 13.1.2 and  14.0.1) compiles without problem and I can also execute a program using the module. Thus, either my interpretation of the standard is incorrect, or ifort is generous here.

Cheers

mmm

 

 

Hello mmm,

thank you for your investigations! Now what confuses me is that, according to your interpretation, subprograms with automatic arrays (which depend in their shape on dummy arguments) can never be overriden. To me this looks like a serious restriction and surprised me, so I also looked into the standard at the passage (1) you quoted. Especially the following sentence looks promising:

 112.2.2 Characteristics of function results
 [..] If a function result is an array that is not allocatable or a pointer, its shape is a characteristic. 
 If [..] a bound of a function result array is not an initialization expression, the
 exact dependence on the entities in the expression is a characteristic.[..]

As I understand that second sentence (highlighted by me), the bounds may depend on some entities (like this%length) and only must evaluate to the similar bounds for similar values of those entities, which is exactly the case we encountered here ('this' may be one of parent / extended type).

However, as you pointed out, the first sentence seems to restricts the choice of bounds by fixing the extent (ubound-lbound+1) per dimension? Or does, on the contrary, the second sentence relax the condition of the first?

I'd appreciate some guidance in understanding this part since I 'm not a native Fortran speaker - plus I don't want to rely on the ifort's generosity in that point... ;-)

With regards, Ferdinand

PS: Your workaround with accessing the component (this%varnum) directly instead of using a getter-function is the same I used. However, in that case, all types must be declared in the same module (if this%varnum is private) and one cannot extend the class without modifying the module which contains the abstract parent - since Fortran can only control visibility over modules, not e.g., by 'family'. Which looks like a little design flaw to me.

Hello Ferdinand,

thanks for reading the standard more carefully than I did. I think that you might well be right. The second sentence could indicate that what we would like to accomplish is actually valid Fortran. However, like you I do not really dare to attempt a final interpretation as this is too far out off my area of expertise. At least it would explain why the variant with the derived type component works.

Talking of portability (hope we are allowed to mention other compilers here ;-) your sample code as well as my example above compiles with nagfor 5.3.1(907). However, I have problems in my actual code which has a deeper inheritance hierarchy and a rank-3 array. With gfortran (4.7.1 and 4.8.2) both examples also generate an internal compiler error, so I filed a bug report with them.

Concerning your remark on the visibility of components, I wouldn't call that a little design flaw. IMHO the fact that there is no possibility to allow that extended types access private components of their parents, if they are not specified within the same module, is a major design flaw. If we think in terms of large class hierarchies for larger software projects I want to use data hiding for reasons of security/maintainability. However, putting all source code directly or via some form on include (Fortran or preprocessing) into one module as the sole possibility to achieve this, is of little appeal.

 

Cheers

mmm

 

 

Deixar um comentário

Faça login para adicionar um comentário. Não é membro? Inscreva-se hoje mesmo!