2

Consider the following function

ELEMENTAL FUNCTION int2str(i) RESULT(s)
    INTEGER, INTENT(IN) :: i
    CHARACTER(LEN = 50) :: appo
    CHARACTER(LEN = :), ALLOCATABLE :: s
    WRITE(appo, '(I0)') i
    ALLOCATE(s, source = TRIM(appo))
END FUNCTION int2str

The function, being elemental, is a scalar function (in my case it takes one scalar integer and gives back one scalar character, even though allocatable in length) that applies elementwise to arrays.

Why the output of

print *, '>>>'//int2str([1, 3, 5, 7])//'<<<'

is (unexpectedly to me)

>>>1<<<>>>3<<<>>>5<<<>>>7<<<

whereas the output of

print *, '>>>', int2str([1, 3, 5, 7]), '<<<'

is (expectedly)

>>>1357<<<

?

What I mean is that the function should apply to every one of the four scalar integers composing the array, thus returning a length-4 array each element of which being a string, but it seems to me that its elementwise-ness applies to the whole concatenation of three strings, as though the // operator has precedence over the function's result.

francescalus
  • 30,576
  • 16
  • 61
  • 96
Enlico
  • 23,259
  • 6
  • 48
  • 102

2 Answers2

3

For character concatenation, the expression

'>>>'//['1','3','5','7']

depends on the scalar '>>>' and the array ['1','3','5','7']. As with other intrinsic binary operations where the operands are a scalar and a rank-1 array, the expression is a rank-1 array.

In determining the value of the expression, the scalar operand is treated as an array like

['>>>','>>>','>>>','>>>']

and the expression is equivalent to

['>>>','>>>','>>>','>>>'] // ['1','3','5','7']

Finally, the expression has value where the elements are operands pairwise:

['>>>1','>>>3','>>>5','>>>7']

You can see the parallels with the expression

9+[1,3,5,7]  ! [9,9,9,9]+[1,3,5,7]  --> [10,12,14,16]

When there are two concentation operations going on, the obvious value is the result.


Note that I didn't express this in terms of an elemental function's result. This is partly because the fact the array comes from a function isn't significant. Also, your elemental function is not actually allowed: an elemental function result may not be allocatable.

On the invalid function, Vladimir F has submitted a bug report covering gfortran not detecting violation of the numbered constraint C1290 of Fortran 2008. In that report you can see that if you remove the result(s) and declare int2str as having the allocatable attribute the function is rejected. Some other compilers do already detect violation.

francescalus
  • 30,576
  • 16
  • 61
  • 96
  • Are you sure about your last statement (_not allowed_)? I've actually used it (from which the main question) and it works! After all, the `ALLOCATABLE` attribute refers to `LEN`, not to `DIMENSION`. – Enlico Jan 18 '18 at 23:32
  • The allocatable attribute doesn't apply to the length parameter or the dimension: it applies to the entity as a whole. – francescalus Jan 18 '18 at 23:34
  • So how should I interpret the function be working? BTW, the function I wrote originally is not `ELEMENTAL`, but then I asked to myself "what would happen if I defined it `ELEMENTAL`?" and the question rised. – Enlico Jan 18 '18 at 23:40
  • Owwww, different length strings could mess everything up. I'll let you know tomorrow! – Enlico Jan 18 '18 at 23:47
  • 1
    Indeed: "error #6112: A function with the ELEMENTAL prefix-spec shall not have the ALLOCATABLE attribute. [INT2STR]" when compiled with ifort. Now I have my copy of the F2008 standard in front of me I can see that this is a numbered constraint: C1290 "The result of an elemental function shall be scalar, shall not have the POINTER or ALLOCATABLE attribute." If your compiler does not complain about your function you should complain to your compiler vendor. – francescalus Jan 19 '18 at 09:31
  • What you've hinted at is true, indeed: GFortran 6.2.0 does not complain. There's no vendor to complain, ahah. – Enlico Jan 19 '18 at 09:43
  • There IS a vendor to complain! GCC. I will report that if you don't know how. – Vladimir F Героям слава Jan 19 '18 at 10:03
  • 1
    It is bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83939 now. It is also possible to report to your Linux distribution vendor, but reporting to GCC directly is the best. – Vladimir F Героям слава Jan 19 '18 at 10:14
  • @francescalus and @VladimirF, I do not understand one more thing. It seems to me that the `ALLOCATABLE` attribute applying to entities as a whole uselessly restricts the usability of the elemental functions. The function in the question (without `ELEMENTAL`) had to use an allocatable `s` , the input being a scalar `i`, the output a scalar `s`, even though its length was set at runtime. Am I wrong? BTW, can you suggest me where to find material to have a deeper view on the use of the 'ALLOCATABLE` attribute when used together with `LEN` and/or `DIMENSION`? – Enlico Jan 21 '18 at 15:33
  • I'm not sure I understand what you are asking, @EnricoMariaDeAngelis. That's partly down to the limitations of the "comment" format, so perhaps you could ask this as a new question. – francescalus Jan 21 '18 at 17:24
0

I've surprisingly experienced that result which I didn't expect (>>>1<<<>>>3<<<>>>5<<<>>>7<<<) is indeed the same even if I manually implement the ELEMENTALity of the function, namely

print *, '>>>'//[num2str(1), num2str(3), num2str(5), num2str(7)]//'<<<'

so I was possibly misunderstanding my own words thus RETURNing a length-4 array each element of which being a string. The function is indeed returning an array of strings, and the concatenation applies to every element of the array (the element of the array being stick together without space in between just because they're strings of characters).

Enlico
  • 23,259
  • 6
  • 48
  • 102