Feature request: map-like safe indexing of slices

I am writing Go code in a private context for about one year now and recently I have stepped over a minor inconsistency regarding slices. So basically as maps, channels and type-assertions have an option for a ‘two value read’ -> val, ok := myMap[key] why not adding a similar functionality for slices?

This would look like this val, ok := mySlice[n]. If the requested index n is not present val will be assigned the zero-value and ok will be false.

Yes you can in fact create your own function that does exactly this in 4 loc.

func safeSliceAccessInt(sl []int, idx int) (int, bool) {
        defer func() { recover() }()
        return sl[idx], true // default values will be substituted if sl[idx] panics (0, false)
}

But of course this is a not generic approach.

I argue more from a consistency aspect than an actual feature one.
Regarding arrays I would suggest against this behaviour as their range can be deduced by their type.
I think this would be very Go idiomatic but still I am not fully convinced myself as wether this is a good idea or not as it introduces redundant behaviour (can be easily archived using the above function or checking the slice bounds with len).

Feature wise it gives you an easy way to bypass the bounds check panic.

As stated above this would fit nicely as map, type-assertion and channel provide similar functionality.
No code will be broken as the single value context assignment will be picked in multi assignment context -> a, b := mySlice[n], 5 will result in b == 5 like with maps, channels and type-assertions.

Maybe we could return the actual value at the position like in C as the bool will be false indicating it is not part of the slice. Out-of-bound writes will of course still panic. I don’t think this fits well into Go but maybe worth a thought.

Please discus.

Update: Additional example in the comments.

1 Like

For a feature request, I think it’s important to provide an example use case. Consistency is nice, but it only really matters if people actually use the feature. Can you post some code that is made possible or is made easier to write?

For maps, the “comma, ok” idiom is necessary because there is no other way of finding out if a given index exists. For slices, you can easily determine the size (and in most cases you know the size beforehand), so the “comma, ok” idiom is not necessary.

A part of Go’s philosophy is to have as few different ways as possible of doing a particular task. If there is a multitude of ways to accomplish the same task, the resulting code is harder to read.

1 Like

val, present := myMap[key]
val, ok:= interf.(type)
val, open := <-myChan
if len(mySlice) > n { val := mySlice[n]; ... } // you have to do it like this now
val, present := mySlice[n] // what I am suggesting
I hope this is more clear now and you get what I mean with inconsistentcy.

Well, to be honest, you have to do the full thing:

if len(myslice) > n {
  val := myslice[n]
  // do something with `val`
} else {
  // do the errorhandling
}

vs.

if val, present := myslice[n]; present {
  // do something with `val`
} else {
  // do the errorhandling
}

I do not consider both to much different codewise, but to be honest, the first version is much more explicit about your intend, so I prefer that way. I’d even prefer some hasKey for maps or isOpen for channels over the current way of having a construct that returns one value or two depending on the context.

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.