Description
Go Programming Experience
Experienced
Other Languages Experience
C, C++, Python, Javascript
Related Idea
- Has this idea, or one like it, been proposed before?Does this affect error handling?Is this about generics?Is this change backward compatible? Breaking the Go 1 compatibility guarantee is a large cost and requires a large benefit
Has this idea, or one like it, been proposed before?
Unlike the above proposal, which requires new syntax and is non-orthogonal, this one aims to accomplish the same thing by just adding a new supported type to range
.
Proposal
Currently, ranging over slices and arrays only provides read access since the elements are copied by value. Adding a way to modify them when using range
would enable loops to omit using index variables entirely for most cases, apart from the rare cases when index arithmetic is actually necessary.
This would, among other things, prevent accidentally using the wrong index when writing nested loops.
func ExampleRange() {
nums := make([]int, 5)
for _, n := range nums {
n = 2 // n is a copy so this doesn't modify the slice
}
fmt.Println(nums)
//Output:
//[0 0 0 0 0]
for _, n := range &nums {
*n = 2 // Proposed solution
}
fmt.Println(nums)
//Output:
//[2 2 2 2 2]
}
Language Spec Changes
Range expression 1st value 2nd value
-array or slice a [n]E, *[n]E, or []E index i int a[i] E
+array or slice a [n]E, or []E index i int a[i] E
+pointer to array or slice p *[n]E, or *[]E index i int &p[i] *E
string s string type index i int see below rune
map m map[K]V key k K m[k] V
channel c chan E, <-chan E element e E
integer value n integer type, or untyped int value i see below
function, 0 values f func(func() bool)
function, 1 value f func(func(V) bool) value v V
function, 2 values f func(func(K, V) bool) key k K v V
Informal Change
N/A
Is this change backward compatible?
Unfortunately Go already supports ranging over array pointers (!), so this would change the behavior of such loops. A gofix
rule should be able to update affected loops:
for i, v := range arrayPtr {
+ v := *v
// ...
}
Slice pointers are new and therefore backward compatible.
Orthogonality: How does this change interact or overlap with existing features?
This change arguably increases orthogonality (compared to the current range-over-array-pointer), since it more closely follows the convention that taking a pointer of a value should allow for modifying it.
Would this change make Go easier or harder to learn, and why?
N/A
Cost Description
Tools that understand the type of the expression in range
statements would need to be updated to the new semantics.
Changes to Go ToolChain
vet, gopls
Performance Costs
N/A (likely minimal)
Prototype
N/A
Activity
gabyhelp commentedon Sep 7, 2024
Related Issues and Documentation
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
seankhliao commentedon Sep 7, 2024
I believe the closing comment for #21537 also applies here, this is just a different syntax but with the same limitations.
ianlancetaylor commentedon Sep 8, 2024
Also, as the proposal points out, this change is not backward compatible. We are not going to make a language change that causes valid code to have one meaning in release 1.X and a different meaning in release 1.X+1. (We did such a change once, as described at https://go.dev/wiki/LoopvarExperiment, but that was a special case that we aren't going to repeat.)