Allow subarray indexing as input to pure and elemental functions

It would be awesome if elemental (and perhaps pure) functions could be used with subarray indexing (which is already great in Fortran), that would save a lot of unnecessary temporary “index” arrays. I’m not sure about anyone else on this forum, but as I use elemental functions as much as possible, I also find myself also having very often to “prepare” index arrays to feed such functions

Imagine something like:


! This is a dumb integer power
elemental function int_power(x,i) result(x_pow_i)
   real, intent(in) :: x
   integer, intent(in) :: i 
   real :: x2,x_pow_i
   select case (i)
      case (0); x_pow_i = 0.0
      case (1); x_pow_i = x
      case (2); x_pow_i = x*x
      case (3); x_pow_i = x*x*x
      case (4); x2 = x*x; x_pow_i = x2*x2
      case default;  x_pow_i = x**i
   end select 
end function int_power

Now, if you want several powers you need to do


integer, allocatable :: even(:)
real, allocatable :: powers(:)

even = [0,2,4,6,8]
powers = int_power(2.0,even)

! or
powers = int_power(2.0,[(j,j=0,8,2)])

While with subarray-index-enabled functions, it would be simply

powers = int_power(2.0,0:8:2)

Simple, optimizeable, readable, concise. I would use that a lot.

The simplest usage would be to return an array with those same indices

elemental integer function self(i) result(j)
   integer, intent(in) :: i
   j = i
end function self

which could be used like:

integer, allocatable :: i(:)
i = self(-53:103:2)
print *, i ! -53 -51 -49 -47 .....

I guess the same restrictions as to working with elemental functions would apply, that probably wouldn’t be hard to implement in current compilers. Thoughts?

You can write

powers = int_power(2.0,seq(0,8,2))

where seq is a user-defined function that some Fortran libraries have. I don’t know if it’s worth expanding the language to allow 0:8:2 instead.

In R, 1:3 is an expression returning [1,2,3] (or c(1,2,3) in R syntax). If x is an array you can write x[1:3] to get the first three elements. What I have stumbled over is that x[1:n-1] is equivalent to x[(1:n)-1] and not x[1:(n-1)] as in Fortran (if [] is replaced with ()).

Here was my suggestion for expanding the functionality of elemental procedures.

I also have my colon function that does exactly that.
My feeling is that if a compiler could use subarray indexing, the indices could be passed to the routine by value instead of by reference, thus maybe avoid to reserve a memory location for that. Would that be faster, I guess?

Yup, that is definitely another limitation I stumble upon all the time!

@FedericoPerini, can you please open up an issue at GitHub - j3-fortran/fortran_proposals: Proposals for the Fortran Standard Committee for this? So that we have the idea and the associated discussion documented. It seems that you want a simpler syntax to create arrays, just 0:8:2 instead of [(j,j=0,8,2)].

1 Like

Sure, will do. Your view of this makes me think that I’m not sure if there are subtle differences between “allowing subarray indexing as an input to pure and elemental functions” and “use subarray indexing as an array initializer”. Perhaps they’re the same thing in most cases…

1 Like

A straightforward link is with array-based do loops and do concurrent/forall- like loops:


! subarray indexing
do I = 1:9:2
end do

! Array loop
do I = [1,53,24,13,-999]
end do
do I = my_array
end do

I moved this topic into a separate thread here, so that we are not “polluting” the F202Y thread.

Here is the github issue: Allow subarray indexing as input to pure and elemental functions · Issue #282 · j3-fortran/fortran_proposals · GitHub

1 Like

That is this issue:

2 Likes

I think if the purpose is to avoid typing a couple of characters in order to define an integer array, then adding this kind of redundant syntax is not productive. It just makes it more difficult on the programmer to learn the new stuff, and it makes it more difficult on the compiler writers to handle the new syntax and to implement it efficiently.

However, if the new syntax is intended to extend the language to allow triplet notation in new ways, or to treat triplets as a new syntax token, then I think it might be an interesting idea.

Finallly, I realize this is probably just meant to be an example application, but if you really did want to compute powers of a number for a range of integers that could be specified with triplet notation, then something like

powers(1) = 1.0
do i = 2, 5
   powers(i) = powers(i-1) * 4.0
enddo

is probably clearer and simpler for the compiler to optimize. This recursive approach requires effort proportional to N, whereas the original code which evaluates the powers individually requires effort proportional to something like N**2 or N*log(N) (depending on how exactly each power is evaluated).

My point is to not let the language syntax lead the programmer in the wrong direction, the underlying algorithms and the clarity of the code are always more important.

1 Like

Thank you, that was exactly my intent - pure and elemental functions allow awesome things to be done with array data, if array indexing was extended to them, any elemental / pure function would de facto also become an array. That would be 1) very useful; 2) a fantastic way to strengthen Fortran’s greatest strength (arrays) 3) produce high performance programs with a modern, user-likeable style!

And yeah that was a pretty dumb example….

After I posted, it occurred to me that the statement

powers = [(int_power(2.0,j), j=0,8,2)]

is roughly the same number of characters to compute the same result with the existing syntax. This moves explicitly the loop to “outside” the procedure call. If int_power() is an elemental function, then it is not clear whether the loop is “outside” or “inside” the function. I think compilers can implement it either way. If it is “inside” then the optimizer might catch the recursion.

2 Likes