2

Let's assume a function that works for a string of any length str:

Two different alternatives came to my mind, but I am not sure they are exactly the same or which one is a better practice.

Way-1

function func_name(str) result(ouput)
        character(len=*), intent(in) :: str
        ...
     end function func_name

Way-2

function func_name(str) result(ouput)
        character(len=:),allocatable, intent(in) :: str
        ...
     end function func_name

2 Answers2

2

The two approaches are not the same: one has a dummy argument with assumed length, and one with deferred length. These mean entirely different things.

That said, in this case there three main differences:

  • the actual argument for the second func_name must be allocatable/deferred length
  • the second func_name is such that it must have an explicit interface available when being referenced; the first need only have an implicit interface (which you'll be giving anyway, right?)
  • only in the second form can the dummy argument be passed on to an allocatable dummy

As to why there's little difference beyond that: the dummy argument is intent(in) (and not a pointer). This means that you can't change its value, you can't (in the second) change the allocation status. Simply, there's no reason for using deferred length if you can't change any property (except in the case of passing to other intent(in) allocatable/pointer dummies). Nearly any reference/use of the dummy argument will make can be done with either form.

Stick to using assumed-length when you can.

Finally, character length isn't a terribly special aspect to consider, so many of the points of a related question apply.

francescalus
  • 30,576
  • 16
  • 61
  • 96
1

Why not try it in a code?

ijb@ijb-Latitude-5410:~/work/stack$ cat char.f90
Program test

  Implicit None

  Character( Len = 3 )              :: str1
  Character( Len = : ), Allocatable :: str2

  Allocate( Character( Len = 4 ) :: str2 )

  Write( *, * ) func_name_1( str1 )
  Write( *, * ) func_name_2( str1 )
  Write( *, * ) func_name_1( str2 )
  Write( *, * ) func_name_2( str2 )
  

Contains
  
  Function func_name_1( str ) Result( output )
    Implicit None
    Integer :: output
    Character( Len = * ), Intent( In ) :: str
    output = Len( str )
  End Function func_name_1

  Function func_name_2 (str ) Result( output )
    Implicit None
    Integer :: output
    Character( Len = : ), Allocatable, Intent( In ) :: str
    output = Len( str )
  End Function func_name_2

End Program test
ijb@ijb-Latitude-5410:~/work/stack$ gfortran-11 --version
GNU Fortran (GCC) 11.1.0
Copyright © 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

ijb@ijb-Latitude-5410:~/work/stack$ gfortran-11 -std=f2008 -Wall -Wextra -fcheck=all -g -O char.f90
char.f90:11:29:

   11 |   Write( *, * ) func_name_2( str1 )
      |                             1
Error: Actual argument at (1) to allocatable or pointer dummy argument ‘str’ must have a deferred length type parameter if and only if the dummy has one

So for the second function form to be correct the actual argument must have a deferred length, ( Len = : ). You generally want the first form.

Ian Bush
  • 6,996
  • 1
  • 21
  • 27
  • The requirement on the actual argument for the second form is slightly stronger: it must be deferred length _and allocatable_ (it can't be deferred length and pointer). – francescalus Nov 24 '21 at 16:39