Live data from Hacker News

How Go detects struct copies with sync.noCopy

func25.dev

41–50 of 82 posts

Re: How Go detects struct copies with sync.noCopy

#41
post #30

I spoke with Aliaksandr Valialkin (author of noCopy) and he gave me his reasons: - https://x.com/valyala/status/2088638160242683954 He also gave an answer of what he would change now: https://itnext.io/go-evolves-in-the-wrong-direction-7dfda8a1... It seems he's not happy anymore with the new direction of Go because they're implementing things from other languages.

> I'd remove user-defined generics from Go, and all the overcomplicated shit related to them, including iterator functions.

Go advances one blub ragequit at a time.

Re: How Go detects struct copies with sync.noCopy

#43

This feels like it should ideally be something public in the structs package so anyone can leverage it, not just a specially blessed internal thing for the sync package.

It's not a specially blessed type. As the article says, anything that implements sync.Locker acts like this.

Re: How Go detects struct copies with sync.noCopy

#44
post #7

Earlier quoted context omitted.

This feels like a style complaint and not one about substance. An inaccessible (because it's named _) zero-length struct field is just another kind of metadata. It also doesn't require you to pollute the method set, which would be a bigger issue. The real hack to me is that anything which simply has Lock() and Unlock() methods is considered uncopyable.

Coming from Rust anyway (can't say I'm familiar with Go), nothing about having it as a trait would pollute the method set, traits don't have to have methods (e.g. pin, unpin, send, sync, etc.). Yes a zero length field can be metadata and this is a style complaint but a struct's fields are traditionally its data and the type is its metadata, I feel like it's harmful to mix these two as I at least wouldn't generally lo…

Rust has similar zero-sized-types, probably the most 'magical' being PhantomData.

Re: How Go detects struct copies with sync.noCopy

#45
post #26

Earlier quoted context omitted.

RAII has the advantage that you can't forget to do it, but defer has the advantage that you can handle failure in ways other than panicking. Of course, in many cases (e.g. closing a file), there's generally not much you can do anyway even if you want to handle the error directly, but at least it's possible.

Rust can handle that with RAII without panicking just fine. And not only Rust..

Sure, you can just ignore errors entirely, and this is what Rust actually does today, at least for std::fs::File. The only other option within RAII that I can think of is that you can mutate some external, longer-lived state.

The primary way to deal with error-on-clean-up in RAII languages is to not rely exclusively on RAII for it. Rust's File type, for example, has sync_data and sync_all methods (which, to be fair, only even need to be called for writable file handles). I don't think there's anything wrong with this approach, but it ends up being just as explicit and therefore forgettable as defer.

It should be noted that you can (at least in Rust) actually implement defer using RAII; see e.g. the scopeguard crate. Since RAII is block-scoped, this defer is also block-scoped (like Zig) rather than function-scoped (like Go).

Re: How Go detects struct copies with sync.noCopy

#46

Earlier quoted context omitted.

Go's full of hacks, and holds no shame over it. Zero-initialized everything, and proceeding to 'defer' instead of RAII, generic builtin types despite lack of generics (until recently), no builtin list type, slices having capacity... This was Go's design philosophy until Rob Pike left - to do the simple thing simply and not try to be clever about it.

> no builtin list type Wait, which thing do you mean by a "list type" ? A growable array type like Rust's Vec or C++ std::vector or the ArrayList type seen in several languages ? Or do you mean a linked list type akin to C++ std::list or std::forward_list or Rust's std::collections::LinkedList ? "List" is vague, which is appropriate if you're talking about very high level abstractions where it doesn't matter how it w…

Yeah, I really don't see much of a reason for Go to get a first-party linked list type. In most cases in non-list-oriented languages the performance and ergonomics are awful compared to a competent growable array type, the mechanical sympathy of "real" linked lists is generally terrible.

Plus they're extremely easy to build if you truly have a good use for one, particularly with generics.

Re: How Go detects struct copies with sync.noCopy

#47

Earlier quoted context omitted.

How is this simple? It's basically a hint to `go vet` that uses a special interface pattern. I'm baffled by what some people call "simple" lol

How much additional complexity do users need to be aware of when writing new code because of the way this was implemented? Adding new features makes the language bigger, for something that Claude tells me is used 20 times in total in the entire Go codebase.

I don't know the answer to those things, it feels like it's sort of on the one saying "This is simple" to explain why.

Re: How Go detects struct copies with sync.noCopy

#48
post #36

Earlier quoted context omitted.

Those are integrated in the compiler and don't need a second tool to work. Also, AFAIK, they only leverage standard language behaviour and are not a hardcoded special case.

Nearly everything in that module relies on at least some hardcoded compiler magic (what Rust calls "language items", with a `#[lang = "..."]` attribute on the definition). The only exception is `Send`—and even that is still an auto trait, which on stable Rust can only be defined by the standard library. (There are plans to also remove the lang-item status from `Unpin`.)

Fair point, I was only looking at the structs, not the traits.

Re: How Go detects struct copies with sync.noCopy

#49

Earlier quoted context omitted.

Go's full of hacks, and holds no shame over it. Zero-initialized everything, and proceeding to 'defer' instead of RAII, generic builtin types despite lack of generics (until recently), no builtin list type, slices having capacity... This was Go's design philosophy until Rob Pike left - to do the simple thing simply and not try to be clever about it.

> no builtin list type Wait, which thing do you mean by a "list type" ? A growable array type like Rust's Vec or C++ std::vector or the ArrayList type seen in several languages ? Or do you mean a linked list type akin to C++ std::list or std::forward_list or Rust's std::collections::LinkedList ? "List" is vague, which is appropriate if you're talking about very high level abstractions where it doesn't matter how it w…

[deleted]

Re: How Go detects struct copies with sync.noCopy

#50

Earlier quoted context omitted.

How much additional complexity do users need to be aware of when writing new code because of the way this was implemented? Adding new features makes the language bigger, for something that Claude tells me is used 20 times in total in the entire Go codebase.

I don't know the answer to those things, it feels like it's sort of on the one saying "This is simple" to explain why.

Because it doesn't expand the language and force the user to learn new features, it instead puts the ugliness deep in the library where nobody needs to interact with it.
Post reply on HN