Skip to content

Finalizer vs destructor #60596

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
EArminjon opened this issue Apr 23, 2025 · 2 comments
Closed

Finalizer vs destructor #60596

EArminjon opened this issue Apr 23, 2025 · 2 comments

Comments

@EArminjon
Copy link

EArminjon commented Apr 23, 2025

Hello,

I open this issue to discuss about the Finalizers and the main concept of destructors. Finalizers smell like a small bandage on top of the language. The C++ language have the destructor concept which is (for me) cleaner, easier to use/understand and achieve if i'm not wrong the exact same behavior.

What are the benefits for Dart to use Finalizers instead of something like destructors ?

The usage feel a bit over complexe for a simple feature (maybe not technicaly, sorry !)

To use Finalizer in dart :

We need to :

  • define a static Finalizer
  • attach the Finalizer in constructor
  • detach the Finalizer in the close method
class Database {
  // Keeps the finalizer itself reachable, otherwise it might be disposed
  // before the finalizer callback gets a chance to run.
  static final Finalizer<DBConnection> _finalizer =
      Finalizer((connection) => connection.close());

  final DBConnection _connection;

  Database._fromConnection(this._connection);

  factory Database.connect() {
    // Wraps the connection in a nice user API,
    // *and* closes connection if the user forgets to.
    final connection = DBConnection.connect();
    final wrapper = Database._fromConnection(connection);
    // Calls finalizer callback when `wrapper` is no longer reachable.
    _finalizer.attach(wrapper, connection, detach: wrapper);
    return wrapper;
  }

  void close() {
    // User requested close.
    _connection.close();
    // Detach from finalizer, no longer needed.
    _finalizer.detach(this);
  }
}

To use destructor In c++ :

We need to :

  • define the destructor
class Database {
public:
    Database() : _connection(new DBConnection()) {}

    void close() {
        if (_connection) {
            _connection->close();
            delete _connection;
            _connection = nullptr;
        }
    }

    ~Database() {
        close();
    }

private:
    DBConnection* _connection;
};

If i'm not wrong other language like Rust, Python, Swift, Objective-C, PHP follow this way.

Why Dart don't use it ?

@mraleph
Copy link
Member

mraleph commented Apr 23, 2025

Dart is a garbage collected language. Objects are never really truly destroyed - they just become unreachable and disappear and the space which was occupied by them is reclaimed in bulk by GC (or more specifically by a sweeper which is a part of the GC).

This means destructors don't really fit. They are a better fit for languages which use more immediate means of memory management - destroying objects immediately as the last reference to them disappears. This usually requires some blend of lexical scope based, type system based and reference counting based memory management.

Swift and Objective-C are using reference counting.

Rust uses affine typesystem and has Arc as a fallback for when a more complex ownership sharing is needed.

Default implementations of Python and PHP are using reference counting with fallback cycle-collectors.

Python's and PHP's choice to expose immediate destruction to developers (__del__ and __destruct respectively) actually put a serious limitation on evolution of runtimes for these languages - because it leaks implementation detail (reference counting) and can't be reproduced one-to-one using more efficient memory management techniques (GC). So you can see more performant implementations like PyPy and HHVM diverging from the default behavior when it comes down to these methods. Anyway, I digress.

@mraleph mraleph closed this as completed Apr 23, 2025
@EArminjon
Copy link
Author

Thanks for the detailed explanation. I understand why destructors don’t fit Dart’s GC model. I’ll stick with Finalizer for resource cleanup.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants