Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

foreach loop #116

Open
Leonard-Reuter opened this issue Dec 16, 2019 · 10 comments
Open

foreach loop #116

Leonard-Reuter opened this issue Dec 16, 2019 · 10 comments
Labels
Clause 11 Standard Clause 11: Execution control

Comments

@Leonard-Reuter
Copy link
Contributor

Leonard-Reuter commented Dec 16, 2019

Allow for foreach loops:
eg.

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

instead of

do i=1, SIZE(array)
    write(*,*) array(i)
end do
@gronki
Copy link

gronki commented Dec 16, 2019 via email

@Leonard-Reuter
Copy link
Contributor Author

It is not even Fortran???

I was a bit distracted when I wrote it. However, I edited it after max. 5 mins, which is 2 hours before you commented =/.

@jacobwilliams
Copy link

PSA: edits are not reflected in the email notifications. If someone is only viewing these via email, they never see any edits. :)

@certik
Copy link
Member

certik commented Dec 16, 2019

That is an interesting idea (probably the final : is not needed in the syntax?). Because Fortran's syntax for iterating over arrays is so simple, I usually like to have an index i, rather than the element itself, because typically (but not always) I want to do more with the matrix than just access the element. Also it generalizes nicely to multidimensional arrays, which the above syntax does not (I think).

@Leonard-Reuter
Copy link
Contributor Author

Leonard-Reuter commented Dec 16, 2019

That is an interesting idea (probably the final : is not needed in the syntax?). Because Fortran's syntax for iterating over arrays is so simple, I usually like to have an index i, rather than the element itself, because typically (but not always) I want to do more with the matrix than just access the element. Also it generalizes nicely to multidimensional arrays, which the above syntax does not (I think).

Jup, I deleted the :.

I sometimes prefer the foreach loop, if I have some kind of nested object oriented code: ie:

type :: Molecule_t
    type(Atom_t), allocatable :: atoms(:)
end type Molecule_t

And later:

subroutine Foo(molecules)
    type(Molecule_t), intent(inout) :: molecules(:)
    integer :: i, j

    do i=1, SIZE(molecules)
        do j=1, SIZE(molecules(i)%atoms)
            call molecules(i)%atoms(j)%Do_something()
        end do
    end do
end subroutine Foo

Would reduce to (probably the variables molecule and atom are best off as pointers?):

subroutine Foo(molecules)
    type(Molecule_t), intent(inout) :: molecules(:)
    type(Molecule_t), pointer :: molecule
    type(Atom_t), pointer :: atom

    do molecule in molecules
        do atom in molecule%atoms
            call atom%Do_something()
        end do
    end do
end subroutine Foo

@certik
Copy link
Member

certik commented Dec 16, 2019

@libavius thanks for the use case.

@Leonard-Reuter
Copy link
Contributor Author

@libavius thanks for the use case.

It could analogoulsy work for multidimensional arrays: (Note that the slicing of an array is determined by the way it is written in the memory.)

subroutine Foo(tensor)
    real(real64), intent(inout) :: tensor(:,:,:)
    real(real64), pointer :: matrix(:,:), vector(:), scalar

    do matrix in tensor
        do vector in matrix
            do scalar in vector
                call Do_something(scalar)
            end do
        end do
    end do
end subroutine Foo

However, this is not really advantageous compared to the obvious way to do it.

@Leonard-Reuter
Copy link
Contributor Author

Leonard-Reuter commented Dec 17, 2019

This could also enable some pythonic 'list' (here: array) comprehension:

type(Atom_t) :: atoms(n)
integer :: charges(n)

charges = [(atom%Get_charge(), atom in atoms)]

instead of:

integer :: i
type(Atom_t) :: atoms(n)
integer :: charges(n)

charges = [(atoms(i)%Get_charge(), i=1, n)]

EDIT: it is actually easier, if Get_charge ist elemental:

type(Atom_t) :: atoms(n)
integer :: charges(n)

charges = atoms%Get_charge()

@jacobwilliams
Copy link

Also, how about adding Python iterator like capability to a derived type? That would be very interesting.

@arjenmarkus
Copy link

arjenmarkus commented Jan 6, 2020

There is the proposal on coroutines and iterators - [https://j3-fortran.org/doc/year/19/19-169.pdf] (see #60). That would definitely cover the kind of loop that is being discussed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Clause 11 Standard Clause 11: Execution control
Projects
None yet
Development

No branches or pull requests

5 participants