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

Elemental function with allocatable attribute

Noro
Beginner
612 Views

Hello,

I need to create a elemental function with returning a variable-length string. To do so I use a allocatable object. But the ifort compiler return the error with code 6112 when gfortran do this very well. So is there a way to do this kind of function with ifort ?

Cheers.

 

0 Kudos
1 Solution
IanH
Honored Contributor II
612 Views

Depending on the situation, it may be appropriate to wrap the allocatable character object in a derived type, and return that instead.

module m
  implicit none
  
  type :: string
    character(:), allocatable :: item
  end type string
contains
  elemental function fun(x)
    integer, intent(in) :: x
    type(string) :: fun
    fun%item = repeat('x', x)
  end function fun
end module m

program p
  use m
  implicit none
  type(string), allocatable :: out(:)
  integer :: i
  
  out = fun([1,2,3,4,5])
  print "(a)", (out(i)%item, i = 1, size(out))
end program p

 

View solution in original post

0 Kudos
7 Replies
FortranFan
Honored Contributor II
612 Views

Fortran standard states in C1290, "The result variable of an elemental function shall be scalar, shall not have the POINTER or ALLOCATABLE attribute, and shall not have a type parameter that is defined by an expression that is not a constant expression."

You write, "need to create a element(al) function with returning a variable-length string": is the length of the return string a constant expression of dummy argument(s) which would be INTENT(IN)?  Then you can make use of this fact in defining the function result string length.

0 Kudos
IanH
Honored Contributor II
613 Views

Depending on the situation, it may be appropriate to wrap the allocatable character object in a derived type, and return that instead.

module m
  implicit none
  
  type :: string
    character(:), allocatable :: item
  end type string
contains
  elemental function fun(x)
    integer, intent(in) :: x
    type(string) :: fun
    fun%item = repeat('x', x)
  end function fun
end module m

program p
  use m
  implicit none
  type(string), allocatable :: out(:)
  integer :: i
  
  out = fun([1,2,3,4,5])
  print "(a)", (out(i)%item, i = 1, size(out))
end program p

 

0 Kudos
Noro
Beginner
612 Views

IanH your solution is interesting but a bit heavy to use because you need to declare your string type every time you need to call the function. And your type string is a hidden character allocatable, so why the compiler do not allow the character allocatable directly ?

FortranFan I try to combine what I understood of your comment into a small example but it compiles find but did not work correctly. So I probably miss-understood. Here is my example:

 

module test3_mod
    implicit none

contains

    elemental function leng(args) result(num)
        implicit none
        integer, intent(in) :: args
        integer             :: num
        
        if (args >=0) then
            num= args +2
        else 
            num= -args +3
        endif
        return
    end function leng

   elemental function func(args) result(string)
        implicit none
        integer, intent(in) :: args
        character(len=leng(args)) :: string

        string=repeat('x',leng(args))
        return
    endfunction func
end module test3_mod

PROGRAM test3
    use test3_mod
    implicit none

    integer, parameter :: n=10

    print *, 'start'
    print*, '.'//func( (/1,10/) )//'.'
    print *, 'normal stop'
    
end  

 

0 Kudos
IanH
Honored Contributor II
612 Views

The compiler does not allow the allocatable attribute on an elemental function result because the language does not permit it.

The language does not permit the allocatable attribute on an elemental function result because, conceptually and practically, it does not make sense.  Being allocatable implies that characteristics, other than the value, of the function result can vary from call to call of the function, such as the length of the function result in this case.  Elemental functions can be invoked as part of setting the value of an array - that is what they are primarily for - and in that context, variation in characteristics, other than the value, from element to element in an array is not permitted.

When the allocatable character thing is made a component of a derived type, then the allocation status of the component and aspects such as the length of the component are then considered part of the value of an object of the derived type (see F2008 4.5.8).  From the perspective of objects of the derived type (rather than looking at the component), the function result can no longer potentially differ in type parameters from call to call - there are no type parameters at the level of the derived type to vary.

Wrapping an allocatable/pointer object as a component of a derived type to permit its use in array-like contexts is a very common thing to do in modern Fortran - it is how you implement arrays of pointers, or arrays of arrays, or arrays of polymorphic objects that might differ in dynamic type from element to element.

That version of gfortran has a bug - one that ifort had a few versions ago too.  The release of gfortran I have here (6.3.1) correctly rejects the code.

For similar reasons as to why allocatable results are prohibited (plus perhaps to make things a little simpler for implementations), the type parameters of the function result of an elemental function must be specified by constant expressions.  The value of a constant expression cannot depend on the value of a dummy argument, and cannot require the execution of a user supplied procedure, but that is what the code in #4 does.  Because this is a constraint, ifort should issue a diagnostic for the non-conforming code in #4, the absence of such a diagnostic is a compiler bug.  Current versions of gfortran do diagnose the error in the program.

 

 

0 Kudos
FortranFan
Honored Contributor II
612 Views

Romain N. wrote:

.. FortranFan I try to combine what I understood of your comment into a small example but it compiles find but did not work correctly. ..

@Romain N,,

Note the constraint C1290 in the Fortran Standard that says, " shall not have a type parameter that is defined by an expression that is not a constant expression".  So look in section 7.1.12 of the standard on "Constant Expression" and the limitations of such an expression.

That said, it would appear to me if you were to change the result variable declaration to be something like, say,

   ..
   character(len=abs(args)+2) :: string
   ..

then it should be Ok per my interpretation of C1290 since ABS is a standard intrinsic elemental function (but note I am more often than not wrong on such matters).  Again Intel Fortran compiler compiles such code without complaints but the executable doesn't work as expected; I don't know if the use is list-directed IO or with the elemental function.  Note gfortran gives an error with the elemental function, "Dummy argument 'args' not allowed in expression at (1)"

I suggest you follow up further with Intel team on this.

 

0 Kudos
Noro
Beginner
612 Views

@IanH, @FortranFan :

Thanks to your two explanations, I understood why it makes no sense to try directly this kind of implementation. I flag IanH respond as the best reply because it gives a good alternative to do this function using a derived type.

Thank you for your time.
 

0 Kudos
Kevin_D_Intel
Employee
612 Views

I reported the ifort defect of not properly flagging the non-conformant code in post #4 that IanH describes in post #5.

(Internal tracking id: DPD200417031)

0 Kudos
Reply