Language: Static extension methods: implement abstract class

Created on 26 Jul 2019  路  9Comments  路  Source: dart-lang/language

Will it be possible to static extension methods to implement some abstract classes (interfaces), like it possible extension to implement protocol in Swift, e.g.:

protocol Foo {
    func foo()
}

extension FooExt : Foo {
    func foo() {
        // some code
    }
}

Such a feature helps a lot to extend primitive type to use for framework's purposes. For example, imagine that we develop an http framework, we can extend String, Map, etc. to provide capability to return it as response to the request, e.g.:

abstract class HttpResponder {
  FutureOr<void> toResponse(Context context);
}

extension HttpStringExt on String implements HttpResponder {
  FutureOr<void> toResponse(Context context) => context.write(this);
}

typedef HttpHandler = HttpResponser Function(Context context);

HttpResponder strHandler() => 'Hello world';
question

Most helpful comment

Just presenting a use case, I am porting some Swift code over to Dart, and they make use of extensions to implement protocols on classes imported from other packages.

https://github.com/uber/RIBs/blob/master/ios/tutorials/tutorial1/TicTacToe/Root/RootComponent%2BLoggedOut.swift#L27

Something like:

class Foo {
  String get foo => "foo";
}

abstract class Protocol {
  String get bar;
}

extension on Foo implements Protocol {
  String get bar => "bar";
}

Is there a possibility this can be added in the future? Is this a complex feature to implement now that we have static extension methods?

All 9 comments

No, this will not be possible with static extension methods.
The static extensions are inherently static. There is no run-time component to them.

As such, passing a String extended by HttpStringExt to something expecting an HttpResponder will fail. At run-time you are passing a string where an HttpResponder is expected, and that must fail.

Or, in short, static extension methods are not traits.

Thanks for the quick response 馃槉
Is it considered to be added to the language in the future? Are there any possibility of it?

Some ideas in this space have been under discussion for a while, e.g. here. I don't think there's any strong short term plans in that direction yet though. I'm going to close this issue, since I think it's mostly covered by the issue referenced above - feel free to comment there on how that proposal sketch would/wouldn't address your use case.

Just presenting a use case, I am porting some Swift code over to Dart, and they make use of extensions to implement protocols on classes imported from other packages.

https://github.com/uber/RIBs/blob/master/ios/tutorials/tutorial1/TicTacToe/Root/RootComponent%2BLoggedOut.swift#L27

Something like:

class Foo {
  String get foo => "foo";
}

abstract class Protocol {
  String get bar;
}

extension on Foo implements Protocol {
  String get bar => "bar";
}

Is there a possibility this can be added in the future? Is this a complex feature to implement now that we have static extension methods?

@rrousselGit I've noticed swift has a very large namespace by default, does that have any effect on why they are able to do implementations with extensions? It doesn't seem like it would at first glance, but your reply seems to allude that it might.

My bad, ignore my previous comment. I've misread the code snippet.

I thought it was:

class Foo implements Protocol {
  String get foo => "foo";
  // bar not implemented
}

extension on Foo implements Protocol {
  // implement bar as an extension
  String get bar => "bar";
}

Ahhh, gotcha! Yeah the question is if you can use extensions to make an imported class implement a protocol/interface of some sort. Would be a real nice way to write adapters!

Another question, not sure if this is the right place for this, or if this is for Stack.

import 'package:flutter/widgets.dart';
import 'package:rxdart/rxdart.dart';

main() {}

extension on StreamBuilder<T> {
  static StreamBuilder<T> seeded({Key key, ValueObservable<T> stream, AsyncWidgetBuilder<T> builder}) =>
      StreamBuilder<T>(key: key, stream: stream, initialData: stream.value, builder: builder);
}

class FakeWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StreamBuilder<bool>.seeded(
      stream: Observable.just(true).shareValueSeeded(true),
      builder: (context, snapshot) {
        ///
      },
    );
  }
}

Possible to add static methods? Right now this is invalid, showing error

The class 'StreamBuilder' doesn't have a constructor named 'seeded'.
Try invoking a different constructor, or define a constructor named 'seeded'.dart(new_with_undefined_constructor)

Possible to add static methods? Right now this is invalid, showing error

No. You'd have to refer to the _extension_ name not the type it's on to invoke a static. As a consequence you can't call a static on an unnamed extension. I filed https://github.com/dart-lang/language/issues/617 to discuss whether we should make the definition a warning.

extension Seeded on StreamBuilder {
  static StreamBuilder<T> seeded<T>(...) =>;
}

// usage
return Seeded.seeded<bool>(...);

Yeah for this specific case I can't find a way to make extensions improve over this style of implementation. If we could extend a class with a new constructor or create an extension with its own constructor or add a static method to the original class I believe it would be an improvement.

class ValueObservableBuilder<T> extends StreamBuilder<T> {
  ValueObservableBuilder({
    Key key,
    ValueObservable<T> valueObservable,
    AsyncWidgetBuilder<T> builder,
  }) : super(key: key, stream: valueObservable, initialData: valueObservable.value, builder: builder);
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

mit-mit picture mit-mit  路  3Comments

jonasfj picture jonasfj  路  3Comments

leonsenft picture leonsenft  路  4Comments

dev-aentgs picture dev-aentgs  路  3Comments

panthe picture panthe  路  4Comments