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

proposal: slices: add ForEach function to iterate #70177

Closed
agaraleas opened this issue Nov 3, 2024 · 5 comments
Closed

proposal: slices: add ForEach function to iterate #70177

agaraleas opened this issue Nov 3, 2024 · 5 comments
Labels
Milestone

Comments

@agaraleas
Copy link

agaraleas commented Nov 3, 2024

Proposal Details

Abstract
This proposal suggests adding a ForEach function to Go slices, inspired by the std::for_each function in C++. This function would simplify the iteration process over slices, providing a clear and concise way to apply a function to each element of a slice, enhancing readability and code organization.

Proposal
Add a function ForEach with a possible implementation like:

func ForEach[T any](s []T, f func(T)) {
    for _, v := range s {
        f(v)
    }
}

This function will allow users to apply a specified function to each element in a slice without the need for a for loop, improving a lot readability in situations like this example:

type BankAccount struct {
    Balance int
}

func printBalance(account *BankAccount) {
    fmt.Println(account.Balance)
}

func main() {
    accounts := []*BankAccount{{100}, {200}, {300}}
    slices.ForEach(accounts, printBalance)
}

A ForEach function lets us directly express the intent of the looping which in my opinion improves a lot readability and comprehension of a code, while being as concise as possible.

If community aggrees with the proposal, I would be happy to provide a PR with implementation.
Thank you

@gopherbot gopherbot added this to the Proposal milestone Nov 3, 2024
@seankhliao
Copy link
Member

I believe in the general case this is Map, which would be part of iterators not slices, see #61898

@seankhliao seankhliao closed this as not planned Won't fix, can't repro, duplicate, stale Nov 3, 2024
@zigo101
Copy link

zigo101 commented Nov 3, 2024

No, in the iterator age, the code should be like

package main

import "fmt"

func ForEach[T any](s []T, f func(T)) func(func() bool) {
	return func(yield func() bool) {
		for _, v := range s {
			f(v)
			if !yield() {
		    	return
		    }
		}
	}
}

type BankAccount struct {
    Balance int
}

func printBalance(account *BankAccount) {
    fmt.Println(account.Balance)
}

func main() {
    accounts := []*BankAccount{{100}, {200}, {300}}
    for range ForEach(accounts, printBalance) {}
}

:)

@zigo101
Copy link

zigo101 commented Nov 3, 2024

Or even more graceful:

package main

import (
	"fmt"
	"slices"
)

func ForEach[E any](it func(func(V E) bool), f func(V E)) func(func() bool) {
	return func(yield func() bool) {
		for v := range it {
			f(v)
			if !yield() {
		    	return
		    }
		}
	}
}

type BankAccount struct {
    Balance int
}

func printBalance(account *BankAccount) {
    fmt.Println(account.Balance)
}

func main() {
    accounts := []*BankAccount{{100}, {200}, {300}}
    for range ForEach(slices.Values(accounts), printBalance) {}
}

@DeedleFake
Copy link

It's not Map(), as it doesn't return anything. It is, however, simply an unwieldy wrapper around just doing a for loop manually.

@agaraleas
Copy link
Author

Thank you for your feedback.

  • Why not include it in both iterators AND slices? Since slices is not deprecated and other functions will co-exist in both packages, I don't see why this one as well cannot be included in both as well.
  • Doing a for manually does not express intention of the iteration. It just adds boilerlate code. To be honest, I believe this addition is the exact opposite of being unwieldy. And this is why something similar exists in most of other languages. It only improves readability by being concise giving the intention of the iteration in a single line

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants