Hacker Timesnew | past | comments | ask | show | jobs | submitlogin

Can someone dumb it down for me how the new runtime.AddCleanup is different from much-disliked finalizers in java?


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.


Small hint, JavaScript is in the process of getting a dispose like API, already at stage 3.

https://github.com/tc39/proposal-explicit-resource-managemen...


Good read about this if you are using Typescript and want to start using it now (pun inteded): https://www.totaltypescript.com/typescript-5-2-new-keyword-u...


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.


Sure, just like in many other languages with automatic memory management.


And C# was heavy on `Finalize()`, but now is all about `using/Dispose()`.


This is Go, yet add again, catching up to the lessons learned by the other programming language communities.

As you point out, finalizers are no longer in good grace in Java, not even in .NET, but lets leave that for another thread.

Hence why they are deprecated since Java 9, released in 2017, and a Cleaner queue should be used instead, or try-with-resources.

https://docs.oracle.com/javase/9/docs/api/java/lang/Object.h...

Basically runtime.AddCleanup() is the Go's version of java.lang.ref.Cleaner::register().


It would be better if they didn't learn from the others


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.


"We're special. Hmm, okay that didn't work". Every Go feature.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: