Andra
Andra

Reputation: 1392

Why some garbage collected & OOP programming language doesn't have a destructor?

Consider the case below

When we are using a C API's inside a class to create some data that are allocated in heap using malloc (e.g Object* create_obj()), and we have to call a certain method (void free_obj()) in the end of the class lifetime to free the memory manually.

When a language has a destructor, we can easily put the free_obj in the class destructor so the user does not have to call the free_obj manually and wait until the class get garbage collected.

My question

Upvotes: 1

Views: 415

Answers (2)

Jörg W Mittag
Jörg W Mittag

Reputation: 369584

Languages like Java and Ruby have finalizers, but not destructors. The main reason is that deterministic destruction constrains the implementation in a way that the language designers did not want to do.

Many of the performance tricks that modern high-performance garbage collectors employ would not be possible with deterministic finalization. Ruby and Java do not even guarantee that an object will be collected at all. It is perfectly legal for a Ruby or Java implementation to never collect an object even if it is unreachable.

Even CPython, which has a very simple garbage collector cannot guarantee deterministic finalization. It only guarantees deterministic finalization for non-cyclic object graphs. And the Python community has made it very clear that this is a private internal implementation detail of CPython and not part of Python language semantics, meaning that other implementations (e.g. PyPy, IronPython, Jython) do not have to implement it and are thus free to implement much better garbage collectors.

Upvotes: 3

benjessop
benjessop

Reputation: 1959

Destructors are necessary in allocation based languages, but optional in GC languages like Ruby. Destructor patterns are not to be confused with garbage collection and are, as you said, representative of matching an object lifespan to a scope.

Objects live for a while and then the section of memory said object consumes is marked as available for future objects. Ruby offers two sets of memory: malloc heap and Ruby object heap. malloc heap does not release back to the os unless the memory is unused by Ruby at the end of gc. The latter (a subset of malloc heap) is where most Ruby objects live. The Ruby garbage collector directs its focus here and cleans up often, meaning destructors are, for the most part, unnecessary. Not every object will be collected but languages like Ruby do not guarantee that.

In Ruby variables reference an Object which means an Object is stored somewhere and variables only hold the Object id. If we called a destructor on such an object that has been collected or destructed by another variable it would return nil but possibly the same object id, which could cause issues at run time.

Ruby's define_finalizer is not common practice and developers are discouraged from using it. The method cannot refer to the object it is freeing as the callback is executed after the object is freed, so there's no guarantee it will be called. If a finalizer proc holds reference to self which would make it impossible for the object to be garbage collected, meaning it will never be collected.

Upvotes: 1

Related Questions