Skip to content

proposal: Go 2: Add ability to use the slice expression [a:b] for more readable for loops and intervals. #64079

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

Closed
jxqu3 opened this issue Nov 12, 2023 · 8 comments
Labels
FrozenDueToAge LanguageChange Suggested changes to the Go language Proposal v2 An incompatible library change
Milestone

Comments

@jxqu3
Copy link

jxqu3 commented Nov 12, 2023

Author background

  • Would you consider yourself a novice, intermediate, or experienced Go programmer?
    Intermediate
  • What other languages do you have experience with?
    Rust, Javascript, C#

Related proposals

  • Has this idea, or one like it, been proposed before?
    spec: add range over int, range over func #61405
    • If so, how does this proposal differ?
      In that proposal you can use range with ints, and the more complex loops made using functions can affect performance as iterating over arrays is slower than a normal for loop
  • Does this affect error handling?
    No, it doesn't.
    • If so, how does this differ from previous error handling proposals?
  • Is this about generics?
    No, it isn't
    • If so, how does this relate to the accepted design and other generics proposals?

Proposal

  • What is the proposed change?

Adding the ability to use the [a:b] expression for easier loops. a would be the start and b the end.
Example:

for i := range -1:2 {
    fmt.Println(i)
}

This would print

-1
0
1
  • Who does this proposal help, and why?
    Projects which need a lot of complex loops, specially nested, are pretty hard to quickly read. I think this would help with readability
    For example iterating over mutlidimensional arrays
  • Please describe as precisely as possible the change to the language.
    It would be a exclusive range. This is pretty similar to rust's range operator a..b, but as the a:b syntax is used in slices, I thought it would be more consistant. The a would be optional, just like the slice expression, missing it would mean 0 (:3 would be same as 0:3). Also, this should allow using integer values as a or b
x := 4 * 2
for i := range :x

Maybe the range keyworld could be removed too for simpler syntax, though that might make it too incosistent.
Being able to do it would be insanely helpful to iter over 1D arrays while getting their respective x, y (for performance reasons, it is common to use 1D arrays to represent 2D arrays, to avoid nesting loops.)

  • What would change in the language spec?
    It would be either in the For statement or as a note in the slice expression section, though I feel the former makes more sense.
  • Please also describe the change informally, as in a class teaching Go.
    To make a loop from a to b (exclusive) you can do
for i := range a:b {}
  • Is this change backward compatible?
    Yes, this should be a optional way to make loops, not the only way.
    • Breaking the Go 1 compatibility guarantee is a large cost and requires a large benefit.
      Show example code before and after the change.
    • Before
    for i := 0; i < 10; i++ {
      	for j := 0; j < 10; j++ {
      		println(i, j)
      	}
      }
    • After
    for i := range 0:10 {
      	for j := range 0:10 {
      		println(i, j)
      	}
      }
    
  • Orthogonality: how does this change interact or overlap with existing features?
    It's the same expression as the slice uses. I think this could be used to make new slices too:
x := []int{0:3} // this would interfere and would break backwards compatibility though, as this can compile right now to key/value ({0: 3, 1: 4, 2: 5})
  • Is the goal of this change a performance improvement?
    No, tough it could help to make it easier to use 1D arrays as multidimensional ones.
    • If so, what quantifiable improvement should we expect?
      None
    • How would we measure it?

Costs

  • Would this change make Go easier or harder to learn, and why?
    Possibly easier, as it is a easier way to write loops. When I teach people to code they often get confused by for loops syntax a lot, so this one could make it a bit more understandable.
  • What is the cost of this proposal? (Every language change has a cost).
    The compiler would need to implement this expression for the loops.
  • How many tools (such as vet, gopls, gofmt, goimports, etc.) would be affected?
    gopls and gofmt should understand the syntax to work
  • What is the compile time cost?
    I don't think it would add a noticeably higher compile time
  • What is the run time cost?
    If the compiler compiles to the same machine code as a normal for loop, 0
  • Can you describe a possible implementation?
    I don't have the knowledge to make a implementation for this.
  • Do you have a prototype? (This is not required.)
    No, sadly
@jxqu3 jxqu3 added LanguageChange Suggested changes to the Go language Proposal v2 An incompatible library change labels Nov 12, 2023
@gopherbot gopherbot added this to the Proposal milestone Nov 12, 2023
@tinne26
Copy link

tinne26 commented Nov 12, 2023

See #61405.

@jxqu3
Copy link
Author

jxqu3 commented Nov 12, 2023

See #61405.
Has this idea, or one like it, been proposed before?
#61405
If so, how does this proposal differ?
In that proposal you can use range with ints, here you can set the start and end for more complex loops.

@tinne26
Copy link

tinne26 commented Nov 12, 2023

If you have looked at that issue, Russ already touches on this, see "Why not add a new syntax for more sophisticated integer ranges?".

@seankhliao
Copy link
Member

see above

@seankhliao seankhliao closed this as not planned Won't fix, can't repro, duplicate, stale Nov 12, 2023
@jxqu3
Copy link
Author

jxqu3 commented Nov 12, 2023

If you have looked at that issue, Russ already touches on this, see "Why not add a new syntax for more sophisticated integer ranges?".

I read it, but I still think adding that syntax would make a much simpler solution than adding some functions that iterate over slices, also considering iterating over a slice is slower than a for loop

@jxqu3
Copy link
Author

jxqu3 commented Nov 13, 2023

Sorry if I came out as rude, I'm not a native English speaker so I struggle a bit expressing myself 😅, after rereading what I wrote I think it might seem rude, so I apologize if that's the case.

@tinne26
Copy link

tinne26 commented Nov 13, 2023

Don't worry, it's not a matter of tone or anything. It's simply that this has already been considered and the Golang team decided for a different trade-off (int ranges could indeed be useful, but they are not useful enough to justify such a new feature (and more particularly, new syntax, even if it resembles current slice/array ranges syntax)). Disagreeing with this trade-off is ok, but to change their mind you would have to provide evidence or expose some major issue or use-case that hasn't been properly considered in previous discussions. You didn't provide any of this. As an example, #61405 mentions this:

[...] from the main repo, approximately half of existing 3-clause for loops can be converted to range over integer.

If you could show that from the other remaining half, at least two thirds can be expressed with [a:b] notation, then that could constitute such an argument to give weight to your proposal.

So, it's not a matter of personal opinion. You are entitled to have your own, but as long as the Golang team opinion is also reasonable, such differences are of no consequence. Even when you happen to be intuitively right about something, it doesn't matter unless you also find a way to communicate why you are right and what did the other party miss. In technical contexts like this one, you need to offer at least one of the things previously mentioned.

The Golang team members will also simply "cold-heartedly" close such proposals because they share this implicit understanding about how things work here, and simply don't have the time to write long replies like this to everyone that comes around with a proposal. But yeah, maybe this will help you understand a bit more.

Soon they might decide to "cold-heartedly" lock the discussion too as we are only making noise. 😉

@jxqu3
Copy link
Author

jxqu3 commented Nov 20, 2023

I can't really say a number on how much it would help the Go source code, but I think most the remaining 3 clause for loops could be replaced, as loops that don't go up 1 by 1 are pretty rate.
If you search for loops in this repo, loops that start from something that isn't 0 aren't that uncommon, mostly starting with 1, though some other loops start with others.

// src/slices/sort.go: some of the funcs that start with 1
func Min[S ~[]E, E cmp.Ordered](x S) E {
	if len(x) < 1 {
		panic("slices.Min: empty list")
	}
	m := x[0]
	for i := 1; i < len(x); i++ {
		m = min(m, x[i])
	}
	return m
}

func MinFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E {
	if len(x) < 1 {
		panic("slices.MinFunc: empty list")
	}
	m := x[0]
	for i := 1; i < len(x); i++ { // could be range 1;len(x)
		if cmp(x[i], m) < 0 {
			m = x[i]
		}
	}
	return m
}

// src/math/jn.go: a lot of the maths and crypto code uses for loops starting in numbers other than 1:
// line 135
for i := 2; i <= n; i++ {
	a *= float64(i) // a = n!
        b *= temp       // b = (x/2)**n
}

Also, adding these ranges, or intervals (as range is already a keyword) could be pretty useful for non-loops too (specially for data science)
For example:

// you could use them to easily generating random numbers!
rand.Intn(10;50)
rand.Float64(2.5;123)

// Making slices with numbers from A to B
test := make([]int, 10)
for _, v := range test {
	fmt.Println(v)
 }
 // This prints 0 ten times, if you wanted a list from, say, 10 to 100, with the interval you could do:
 test2 := make([]int, 10;000)
 // This is insanely useful for data science applications
// Also, if a is greater than b, a loop/list should go backwards:
for i := range 100;0 { fmt.Println(i) } // this should print 100 to 0, backwards

@jxqu3 jxqu3 changed the title proposal: Go 2: Add ability to use the slice expression [a:b] for more readable for loops. proposal: Go 2: Add ability to use the slice expression [a:b] for more readable for loops and intervals. Nov 20, 2023
@golang golang locked and limited conversation to collaborators Nov 19, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge LanguageChange Suggested changes to the Go language Proposal v2 An incompatible library change
Projects
None yet
Development

No branches or pull requests

4 participants