It's a lowlight in the language in my opinion; while adding metadata to fields is neat, putting it in an untyped string where the parsing is left to the library is far from ideal. I'm pretty sure that eventually the language will move away from struct tags in favor of a language construct like annotations in other languages, but like with error handling, this will be a long and slow process.
I disagree. Hardly doubt golang will break existing code for that, especially considering that structtags are parsed at compile time. It makes a lot of sense to me that the compiler couldn’t care less about it, when that is 100% a library construct.
The most important difference is that runtime.AddCleanup doesn't pass a reference to the decedent object to the cleanup callback.
This is a big deal, because it means that, once the callback is called, you know that the object is completely dead and will never be reachable by anything ever again. By contrast, if the callback receives a reference to the object as an argument, then it is only mostly dead, because it is still reachable through that reference. If the callback stores a copy of that reference elsewhere before it returns, then the object is no longer unreachable, and the garbage collection that triggered the callback has to be cancelled. This is called "object resurrection" and it can cause all kinds of horrible chaos, e.g., by allowing an object that's part of a reference cycle to be observed in a partially-cleaned-up state wherein its internal invariants might be violated. Writing code that correctly deals with the possibility of object resurrection is very difficult.
By contrast, runtime.AddCleanup mostly works the way you'd expect. There is one footgun, which is that, if the object to be cleaned up is reachable from the cleanup callback, then this will prevent it from ever becoming eligible for garbage collection, it will live forever, and the cleanup callback will never run. You have to be careful not to let that happen. But the consequence of messing this up is merely a resource leak, which is generally much less bad than the kinds of state corruption that object resurrection can cause.
Lots of programming languages with garbage collection went through the cycle of starting out with a finalization API that allowed object resurrection, realizing that this was a bad idea, and deprecating it or discouraging its use in favor of a new API that doesn't have this problem. E.g., Go now recommends runtime.AddCleanup over runtime.SetFinalizer, Java now recommends java.lang.ref.Cleaner over Object.finalize, and Python now recommends weakref.finalize over __del__. JavaScript was fortunate in that it didn't gain support for any kind of finalization until 2021, by which time the hazards of object resurrection were well-understood, so it only has the good API and not the dangerous one.
Note that the new disposable protocol in JavaScript is unrelated to garbage collection; it's more like Go's `defer`. The grandparent is talking about JavaScript's somewhat older FinalizationRegistry.
Can you explain? Because if you don't learn from others you're cursed to repeat the same mistakes. I like to mention Java's generics implementation making up half the language spec and compiler.
Related
Go 1.24's go tool is one of the best additions to the ecosystem in years (290 points, 21 days ago, 194 comments) https://news.ycombinator.com/item?id=42845323
Microsoft Go 1.24 FIPS changes (84 points, 11 days ago, 62 comments) https://news.ycombinator.com/item?id=42965404