j3-fortran / fortran_proposals

Proposals for the Fortran Standard Committee
175 stars 14 forks source link

for loop #241

Open jacobwilliams opened 2 years ago

jacobwilliams commented 2 years ago

Not sure if this has already been proposed or not. But I keep wishing Fortran had something like the python for style loops like this:

for x in [10, 23, 1]:
   do_something(x)

or with zip:

for x,y in zip([10,23,1], ['a', 'b', 'cc']):
  do_something(x,y)

of course, the fortran way would be something like that:

integer :: i  ! just a counter
integer,dimension(3),parameter :: vals = [10, 23, 1]
character(len=2),dimension(3),parameter :: cals = ['a ', 'b ', 'cc']
do i = 1, 3
  call do_something(vals(i), cals(i))
end do

What do people think?

I don't know what the syntax would be...

for (x => [10, 23, 1], c => ['a ', 'b ', 'cc'])
  call do_something(x,c)
end for
certik commented 2 years ago

Yes, Julia also has this feature. I think this can be done, it would bring Fortran closer to Python and Julia.

cmacmackin commented 2 years ago

I like the idea. I think maybe we should use something different than pointer assignment for the syntax though. This is because

  1. It makes it look like the counter variable is being associated with the entire array.
  2. Using a new operator (e.g., ->) leaves open the possibility that it could be overridden for derived types, giving the possibility of custom iterators.

We don't need to think out all the technicalities of how such custom iterators would be implemented right now, but we can at least leave the possibility open for the future.

jacobwilliams commented 2 years ago

Another option is a new .in. operator.

Beliavsky commented 2 years ago

I have wanted the same thing and support the proposal, but note that Impure elemental subroutines can simulate for loops over collections

waynelapierre commented 2 years ago

how about this syntax?

do [x, y] .in. [[10, 23, 1], ['a', 'b', 'cc']]
  do_something(x, y)
end do
Leonard-Reuter commented 1 year ago

The feature is called foreach loop, it is already discussed in https://github.com/j3-fortran/fortran_proposals/issues/116 with the following syntax close to the one by @waynelapierre:

do element in array
    write(*,*) element
end do

ZIP could be an intrinsic function, which would take two 1D arrays of size n and create a 2D array of size 2xn (due to Fortran having column major order. The foreach loop would then iterate over the columns of this array:

do col in ZIP(array1, array2)
    write(*,*) col(1), col(2)
end do

But using ZIP the way you want to would require unpacking variables from arrays, which is discussed in https://github.com/j3-fortran/fortran_proposals/issues/186. It would add a syntax like this:

real :: a(2) = [1,2]
real :: x, y
...
[x,y] = a

and thus allow for what you had in mind by implicit application of array unpacking:

do [x, y] in ZIP(array1, array2)
    write(*,*) x, y
end do

I would be very much in favor of both features. They increase readability of code by a lot.

luizpbraga commented 1 year ago

I like this syntax:

...  
vec = [1,2,3,4]
for (element) in vec do 
   print *, element
end do

Also:

...  
vec = [1,2,3,4]
for (element, index) in vec do 
   print *, element, index
end do

Using the "possible" zip() function:

...  
vec1 = [1,2,3,4]
vec2 = [-1,-2,-3,-4]
for (v1, v2, index) in zip(vec1,vec2) do 
   print *, index, v1, v2
end do

It looks readable to me, and also preserves the "do ... end do" syntax.