Go 1.21 new builtin function clear()

1,987 views
Skip to first unread message

Tharaneedharan Vilwanathan

unread,
Jul 5, 2023, 3:06:58 AM7/5/23
to golang-nuts
Hi All,

Go 1.21 introduces a new clear() builtin function. I see this text in https://tip.golang.org/ref/spec#Clear:

clear(t) type parameter see below

If the argument type is a type parameter, all types in its type set must be maps or slices, and clear performs the operation corresponding to the actual type argument.

I am not able to make sense of it. What does this mean? Any examples on the usage?

Appreciate your help.

Thanks
dharani

Axel Wagner

unread,
Jul 5, 2023, 4:38:54 AM7/5/23
to Tharaneedharan Vilwanathan, golang-nuts
Hi,

this has come up on the issue as well. Robert Griesemer provided an explanation:

If the argument type (the type of the argument provided to clear) is a type parameter (is of type parameter type), all types in its type set (in the type set of the constraint corresponding to the type parameter) must be maps or slices, and clear performs the operation corresponding to the actual type argument (corresponding to the type of the actual type argument with which the type parameter was instantiated).

That is, the sentence is about this situation:

func Clear[T, any, S ~[]T](s S) {
    clear(s)
}
func main() {
    Clear(make([]int, 42))
}

In this case, the type of s is S, which is a type parameter. So `clear` performs the operation corresponding to the type argument - in this example []int.

The sentence is a bit confusing (I've seen this question come up four times now), so it probably should be clarified a bit.

--
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/CAN-HoCn99D-m71aJr3DRzCJvk_c7h8OhG2O4wPC-1Wd2ruEYNg%40mail.gmail.com.

Tharaneedharan Vilwanathan

unread,
Jul 5, 2023, 4:54:43 AM7/5/23
to Axel Wagner, golang-nuts
Hi Axel,

Okay, that helps! Thanks for the details.

Regards
dharani

Henry

unread,
Jul 6, 2023, 1:49:13 AM7/6/23
to golang-nuts
So, if I get this right, clear on map will result in map length equals to zero, but clear on slice is only a value-zeroing operation and the slice length remains unchanged? They seem like two different operations to me. I don't think that built-in clear function is necessary. It doesn't seem like the function has a good reason to be there.

Axel Wagner

unread,
Jul 6, 2023, 2:14:46 AM7/6/23
to Henry, golang-nuts
On Thu, Jul 6, 2023 at 7:49 AM Henry <henry.ad...@gmail.com> wrote:
So, if I get this right, clear on map will result in map length equals to zero, but clear on slice is only a value-zeroing operation and the slice length remains unchanged?

That understanding is correct.
 
They seem like two different operations to me. I don't think that built-in clear function is necessary. It doesn't seem like the function has a good reason to be there.

There is one thing that `clear` allows which is impossible without it and that's removing irreflexive keys (those that contain floating point types/elements/fields which are NaN) from a map.

Whether that's a "good" reason is up for debate, of course. There has been quite a bit of that in the issue already: https://github.com/golang/go/issues/56351
 

Axel Wagner

unread,
Jul 6, 2023, 2:17:39 AM7/6/23
to Henry, golang-nuts
Oh and FWIW: You are right (in my opinion) that the different things `clear` does are, well, different. But note that clear is not the only builtin for which that is the case. `make`, `len` and `cap` all do different things (to varying degrees) on maps, slices and channels.
That's not necessarily a good reason to add more builtins that do different things, but there is precedent.

Henry

unread,
Jul 6, 2023, 3:41:25 AM7/6/23
to golang-nuts
'make' allocates the required memory. 'len' returns the length. 'cap' returns the capacity. The underlying implementation may be different, but the concept is the same. There is no issue with those. 

It is common for a collection to have methods such as 'Add', 'Delete', and 'Clear'. The common interpretation of clearing a collection means removing all items from the collection and setting its length to zero. Clear works like that with map, but it does differently with slice. I would not say replacing the values in a slice with the default values as clearing. Maybe you can call that zeroing, but that's not clearing. Many people would expect after calling 'Clear(slice)' then the slice length should be zero.  That's why I think the function is incoherent. 

Brian Candler

unread,
Jul 6, 2023, 4:37:46 AM7/6/23
to golang-nuts
In principle I agree with the sentiment, in the sense this is what you'd expect from other languages like Python.

However, slices are fundamentally different to maps in Go. Map values contain a pointer to a mutable data structure (that's why you can't insert into a zero map - you have to allocate the structure first).  Slices are structs that contain ptr/len/cap which are never mutated (although the data elements pointed to by ptr may mutate, of course).  To alter the len or cap you have to create a new slice value to replace the old one. e.g.

    a := []int{1,2,3}
    a = a[0:0]   // "clear"

So an in-place "clear" of a slice in the way you suggest, which alters the existing len to zero, would have to take a pointer to a slice, not a plain slice value.

TBH, I don't see the point of the new clear(slice) function.  It clears values up to len, not to cap:

In which case, you might as well just write:
var z T  // zero value
for i := 0; i < len(a); i++ {
    a[i] = z
}

I've never felt the need to do this - certainly not enough to warrant a built-in function.  (I would allocate a new slice, and let the garbage collector deal with the old one)

Axel Wagner

unread,
Jul 6, 2023, 5:14:01 AM7/6/23
to Henry, golang-nuts
On Thu 6. Jul 2023 at 09:41, Henry <henry.ad...@gmail.com> wrote:
'make' allocates the required memory.

Does it? What about channels and maps?

'len' returns the length.

What’s the “length” of a channel? What’s the “length” of a map?

'cap' returns the capacity.

For maps?

These questions are rhetorical, for what it’s worth. I understand how the language works, I just try to illustrate that brushing aside these differences is like me saying “clear clears it’s argument”.

The underlying implementation may be different, but the concept is the same. There is no issue with those. 

It is common for a collection to have methods such as 'Add', 'Delete', and 'Clear'. The common interpretation of clearing a collection means removing all items from the collection and setting its length to zero. Clear works like that with map, but it does differently with slice. I would not say replacing the values in a slice with the default values as clearing. Maybe you can call that zeroing, but that's not clearing. Many people would expect after calling 'Clear(slice)' then the slice length should be zero.  That's why I think the function is incoherent.

Note that this has been discussed on the issue, as far as I remember. Nothing of what you say is wrong. But there are counterpoints. For example, there is no precedence for a function (prefects red or not) that takes a slice and modifies it. For example, append has to return a modified slice.
So I don’t think it really is right to say “people would expect the length of a to be zero after clear(a)”. I think they would be differently surprised.

But really, I’m not super sold on the final semantics of clear either. But these questions have been considered.

Axel Wagner

unread,
Jul 6, 2023, 5:16:02 AM7/6/23
to Henry, golang-nuts
Wow, autocorrect on this phone is fun. I’ll just say that it was supposed to be “predeclared”, not “prefects red”. And leave the other typos uncorrected.
Reply all
Reply to author
Forward
0 new messages