6 ms·
That `clear` on a slice sets all values to their type's zero value is going to be extremely confusing especially coming from other languages (Rust, C#, C++, Jav
by maximilianburke 3y ago
That `clear` on a slice sets all values to their type's zero value is going to be extremely confusing especially coming from other languages (Rust, C#, C++, Java, ...) where the same-named function is used on list-ish types to set their length to zero.
Doubly-so when `clear` on a map actually seems to follow the convention of removing all contained elements.
- klodolph 3y agoSure, although as a Go user, the behavior described is exactly what I’d expect. These new functions are no different from functions that you could write yourself.
- Jabbles 3y agoThe builtin clear() will handle cases like deleting NaN from a map.
- maccard 3y agoI'm a go user, and think it's dumb that: clear(f) fmt.Println(len(f)) will have different results if f is a slice and a map.
- klodolph 3y agoI guess, but that seems expected to me at this point, and consistent within the semantics of how slices and maps work (and other values). Maps are kind of like type map *struct{ len int; ... } Slices are kind of like type slice struct{ len int; ... } We get a lot of convenience by having the pointers auto-dereferenced, but the cost is that the semantics are still different and there are no syntactic markers to remind us of the fact. I don't think any language has really given us something that is completely intuitive here. Python's semantics with the list type are a constant surprise to newcomers. C++’s semantics surprise newcomers. Rust's semantics surprise newcomers. Surprises all around. The best you can hope for is something that is internally consistent. The slice in Go is more or less equivalent to &[] in Rust or std::span in C++. The whole idea of passing a pointer by value is key to understanding the semantics of most modern programming languages. Like, is Java pass-by-value or pass-by-reference? You can argue the point, but whatever label you decide is appropriate for Java, it’s useful to think of Java as passing pointers by value. Same with Python, Rust, Go, etc. This is not intuitive for people who are new to programming.
- steveklabnik 3y ago> The slice in Go is more or less equivalent to &[] in Rust or std::span in C++. My understanding is, to use the Rust/C++ term, slices in Go are owned, but they are not in Rust or C++. That is, they're a pointer + length in the latter two, but a pointer, length, and capacity in Go.
- klodolph 3y agoThe type in Go does not carry ownership information. It is not a useful distinction to say that slices are "owned" in Go.
- steveklabnik 3y agoTypes in C++ don’t carry ownership information inherently either, but they’re still thought of in these terms. I know Go doesn’t often use these terms, which is why I clarified. I think the distinction is useful specifically because it explains why Go slices work differently than in at least those two languages.
- klodolph 3y agoSure, there may be a right way to say this. I have a particular axe to grind when it comes to the word “ownership” of objects in programming. In C++ and Rust there is a very natural sense of ownership in that the owner of an object is who may deallocate the object, and that ownership may be shared with std::shared_ptr<T> in C++ or Rc<T> / Arc<T> in Rust. Ownership is such a useful concept in these languages because it is generally true that somebody must deallocate the object, and it must happen safely. As a very natural consequence, people who spend long hours working in C++, Rust, C, or other similar languages start to associate, very closely, the notions of ownership and correctness. And indeed, ownership is broadly useful outside C++, Rust, and C. Even in a garbage-collected language like Java or Go, it is generally useful to have clear ownership. You don't modify objects that you don't own, or use objects outside their scope. But occasionally, you come across a piece of code where ownership gets in the way. Perhaps some garbage-collected algorithm that transforms data with pointers going all over the place. It probably sounds like a mess, but that is not necessarily true either—it can be perfectly good, correct, readable code. So while ownership is a useful concept for talking about specific pieces of Go code, or specific pieces of Java code, it is not applicable to all Go or Java code, and that’s fine. It’s kind of like talking about code in terms of functions—nearly every language on the planet makes heavy use of functions (or some equivalent), but it’s also true that code does not have to be organized in functions, and you will occasionally see code that does not use functions.
- neonsunset 3y agoC#’s array/span.Clear() does exactly the same - it zeroes them out.
- 6D794163636F756 3y agoIt sounds like they're inheriting the naming from the calloc command. Allocates then 0's the memory. It lines up with the go devs' backgrounds
- esprehn 3y agoGo slices are passed by value so there's no way for clear() to resize the underlying array without reassignment. I suppose it could have been x = clear(x) or clear(&x), but certainly if you understand Go semantics then seeing any function call do Foo(slice) already signals that the call can't modify the length since there's no return value.
- nu11ptr 3y agoThis is a great example of why I dislike Go. It is not obvious that a slice is passed by value while a map is not or why. Therefore every action on it feels a bit weird because of that, and now you have functions like "clear" that take a very non-obvious action. Personally, I'd rather have pass-by-value return an error and only allow pass-by-reference (better: they should have had maps and slices be pointers). I'm not sure I'd ever use a function that set every value to its zero type.
- esprehn 3y agoI agree the semantics seem weird, I've occasionally wanted the equivalent of x = clear(x) but I can't think of a time when I've wanted to set all the values to the zero value. The bug doesn't seem to discuss use cases for it either. The most I could find is: https://github.com/golang/go/issues/56351#issuecomment-1332625286 https://github.com/golang/go/issues/56351#issuecomment-13326... Which boils down to "doing what clear(slice) does cannot be implemented efficiently today" but I'm not sure how having an efficient way to do something folks don't want is useful? There's already a memory clearing optimization in the compiler: https://github.com/golang/go/issues/19266 https://github.com/golang/go/issues/19266 So yeah I'm not sure under what situations folks will use clear(slice).
- aatd86 3y agoYou often do it in Go to avoid pointing at something needlessly which would delay or even keep that something from being garbage collected.
- binwiederhier 3y agoThat's actually a great explanation of why it's not easy to implement the clear function the way it makes sense for slices. However, this is a built-in, not a normal function, so they could make it do whatever they like, including doing the intuitive and desired thing, no? It seems to me that they've just created another "loop variable gotcha" type situation...