Skip to content
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

Add standard interfaces like Disposable as Mixins in the Dart SDK #59678

Open
escamoteur opened this issue Dec 6, 2024 · 7 comments
Open

Add standard interfaces like Disposable as Mixins in the Dart SDK #59678

escamoteur opened this issue Dec 6, 2024 · 7 comments
Labels
area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. type-enhancement A request for a change that isn't a bug

Comments

@escamoteur
Copy link

One of the the great features of OO languages is polymorphism based on known interfaces.
Unfortunately, Dart has neglected to define interfaces that are standard in other SDKs. This makes it impossible to write generic libraries without casting objects to dynamic and try to call a method hoping it will be available, therefore hurting type safety.

The two most missed ones are probably

  • Disposable
  • Serializable

But I'm sure there might be some more. Thanks to mixins it should be possible to introduce such interfaces even today into existing classes of the Dart SDK, Flutter and all packages where it makes sense and improve the situation.

cc @FMorschel

@dart-github-bot
Copy link
Collaborator

Summary: User requests standard interfaces (e.g., Disposable, Serializable) as Dart mixins to improve type safety and generic library development. This would enhance polymorphism and reduce reliance on dynamic casts.

@dart-github-bot dart-github-bot added area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. triage-automation See https://github.com/dart-lang/ecosystem/tree/main/pkgs/sdk_triage_bot. type-enhancement A request for a change that isn't a bug labels Dec 6, 2024
@FMorschel
Copy link
Contributor

@escamoteur
Copy link
Author

as an addition this was my original issue on Listenable that was closed unfortunately
#55816

@Levi-Lesches
Copy link

For Flutter types specifically, flutter/flutter#149466 is the new issue to track

@Reprevise
Copy link

Reprevise commented Dec 6, 2024

Disposable is talked about here: #43490

@lrhn
Copy link
Member

lrhn commented Dec 10, 2024

I'll refer to #43490 for a disposable interface.

For Serializable as an interface, I have opinions.

  • Being serializable is definitely an opt-in feature, so an interface would make sense.
  • When people say "serialization" they often mean toJson, which is a terrible serialization format.
    • And they actually mean "return a map" which is a horribly inefficient way to generate a serialized JSON string.
  • An interface doesn't support deserialization, because that's a static function (otherwise you'd need an object to create an object), so it's serialization only.
  • It's very, very hard to make an serialization format that is optimal for everybody.
    • "JSON" is not a serialization format. For example, it doesn't support cyclic structures.
      You need an interpretation on top.
  • So we can try to abstract over the format.
  • It's hard to make a serialization API that supports all the possible serialization formats that people would want to use.
  • Anything hard-coded into the SDK is likely to become insufficient in the future, maybe beacuse more language features are added, that also need to be serialized, and maybe just because it fails to support the favorite format-of-the-day.

I don't see a platform library provided serialization abstraction as a good choice. If it's not sufficient for anything in practice, it's a waste of code. If it's over-engineered (which is easy if you want to be sufficient for everything), then people will eventually choose a simpler version that matches their needs. Even if it gets just one thing wrong, you'll be better off using a different serialization approach.
And then the platform libraries are stuck with their original implementation, because there will always be some small amount of code that uses it, just because it's there.

As for having to cast objects to dynamic, that omits the option of wrapping.
You can declare:

abstract interface class Disposable {
  void dispose();
}

extension StreamSubscriptionDisposableX on StreamSubscription<X> {
  Disposable get disposable => _StreamSubscriptionDisposable(this);
}
final class _StreamSubcriptionDisposable implements Disposable {
  StreamSubscription<Object?>? _subscription;
  _StreamSubcriptionDisposable(this._subscription);
  void dispose() {
    _subscription?.cancel().ignore();
    _subscription = null;
  }
}

and then you can wrap your objects when you create them and know their type, before passing them to something that wants to dispose them.
"Favor composition over inheritance."

@lrhn lrhn removed the triage-automation See https://github.com/dart-lang/ecosystem/tree/main/pkgs/sdk_triage_bot. label Dec 10, 2024
@escamoteur
Copy link
Author

@lrhn But reality is that we have throughout the Flutter SDK objects that already have a dispose() function. And your extension method above still won't let me check if a type offers an dispose function so I have won nothing.

In relation to the Serializable I agree to you points but then make it a Mappable or JsonReady or what else interface that contains the toJson method. As we don't have reflection we need some safe way to know if expected functions exist

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. type-enhancement A request for a change that isn't a bug
Projects
None yet
Development

No branches or pull requests

6 participants