Why doesn't Go include a contains method for things like slices?

307 views
Skip to first unread message

todd...@icloud.com

unread,
Nov 5, 2019, 3:31:04 PM11/5/19
to golang-nuts
Sorry if this question reveals my newness to Go. I tried searching the mailing list but I couldn't find anything in a quick search. It seems like many languages include the ability to check if an array, or slice contain a particular value. I understand that you could do this easily with a for loop or alternatively use a map instead. However, is there a reason why Go doesn't just have slice.Contains(interface{}) or maybe a builtin contains(mySlice, interface{}) ?

I assume one reason might be because slices could potentially be really large? Or maybe the community feels that a simple for loop is so easy that it is not necessary? I would love to understand this more.

Thank You!
-Todd

Ian Lance Taylor

unread,
Nov 5, 2019, 3:42:58 PM11/5/19
to todd...@icloud.com, golang-nuts
This is basically the generics question: why can't you write a generic
function that operates on slices independently of the type of the
slice element? In the absence of generics, the function has to be
written using an empty interface, which provides no compile-time type
checking. So people just write the loop.

Using the design draft at
https://go.googlesource.com/proposal/+/master/design/go2draft-contracts.md
this would be written as

func Contains(type T comparable)(s []T, x T) bool {
for _, v := range s {
if v == x {
return true
}
}
return false
}

Ian

Tyler Compton

unread,
Nov 5, 2019, 4:57:54 PM11/5/19
to todd...@icloud.com, golang-nuts
Ian's answer addresses your question about the absence of a slice.Contains method, but there have been discussions in the past about adding such a feature to the language itself as well. You brought up the idea of a builtin "contains" function, and I've seen others suggest adding something like Python's "in" operator as well. To most of these proposals, the answer has been "no" because of concerns about hiding a potentially very expensive operation behind a builtin or operator. There's no doubt that:

return myObj in mySlice

... is easier to miss than:

for _, obj := range mySlice {
    if obj == myObj {
        return true
    }
}
return false

On Tue, Nov 5, 2019 at 12:30 PM toddsurfs via golang-nuts <golan...@googlegroups.com> wrote:
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/7d4c52e3-8c0f-4ba6-ae24-67ddb4a07ede%40googlegroups.com.

Robert Engels

unread,
Nov 5, 2019, 5:44:55 PM11/5/19
to Tyler Compton, todd...@icloud.com, golang-nuts
Is it though?

You would have the same problem if you thought the size of mySlice was always small, and it wasn't - range could be quite expensive (or not) - and if that was not valid workable you should be using something other than a slice.

You need understanding of the types and cost of operations in any language, and the naming (or something else) should make the types easily recognizable (and understandable).


Tyler Compton

unread,
Nov 5, 2019, 6:58:46 PM11/5/19
to Robert Engels, todd...@icloud.com, golang-nuts
I agree with you that an original writer of the code should be expected to know that a theoretical "contains" or "in" expression has O(n) properties. However, I've always thought of this from the perspective of someone looking at the code later and trying to identify performance issues. It's easy to identify a potentially very costly iteration through a slice if it's more verbose and always expressed the same way.

Tyler Compton

unread,
Nov 5, 2019, 7:01:54 PM11/5/19
to Robert Engels, todd...@icloud.com, golang-nuts
I should mention that I don't 100% buy this argument and I would still like to see a "slices.Contains" function in the future if/when generics are added. I'm trying (perhaps poorly) to explain what I've seen as the most common argument against adding such a feature.

Robert Engels

unread,
Nov 5, 2019, 7:06:01 PM11/5/19
to Tyler Compton, todd...@icloud.com, golang-nuts
I think that’s splitting hairs a bit. Even if you see the loop you don’t know the cost unless you know the size of a slice. For instance, a lookup in a small slice is actually cheaper than a small map - in memory and speed. So you need to know more than “it’s a slice” to make a judgement. 

On Nov 5, 2019, at 5:58 PM, Tyler Compton <xav...@gmail.com> wrote:



Tyler Compton

unread,
Nov 6, 2019, 10:47:47 PM11/6/19
to Robert Engels, todd...@icloud.com, golang-nuts
That's a good point. Also, now that I think of it, with the help of a profiler it should be straightforward to identify places where iterating over a slice is a problem regardless of how the iteration is expressed. I'm convinced!
Reply all
Reply to author
Forward
0 new messages