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

override extension methods #3321

Closed
SivaramSS opened this issue Sep 5, 2023 · 1 comment
Closed

override extension methods #3321

SivaramSS opened this issue Sep 5, 2023 · 1 comment
Labels
request Requests to resolve a particular developer problem

Comments

@SivaramSS
Copy link

SivaramSS commented Sep 5, 2023

Request to make extension methods behave like actual class member functions. Here is an example, calling type casting Center widget and calling the extension method calls Widget extension method instead of Center extension method. This will allow developers to add functionality to the library or framework without actually modifying the library's source code.
`
import 'package:flutter/material.dart';

  void main() {
    Widget widget = Center(child: Container(width: 50, height: 50, color: Colors.yellow,),);
    widget.foo();
    runApp(widget);
  }
  
  extension WidgetExtension on Widget {
    void foo() {
      print("Widget.foo");
    }
  }
  
  extension CenterWidgetExtension on Center {
    void foo() {
      print("Center.foo");
      child?.foo();
    }
  }
  
  extension ContainerWidgetExtension on Container {
    void foo() {
      print("Container.foo");
      child?.foo();
    }
  }

`

@SivaramSS SivaramSS added the request Requests to resolve a particular developer problem label Sep 5, 2023
@eernstg
Copy link
Member

eernstg commented Sep 5, 2023

Here's an existing proposal which would introduce support for extension methods with late binding: #177. It also illustrates why this is a non-trivial undertaking.

We didn't go in that direction when extension declarations were added to the language, and it would be a radical change of the extension member mechanism to do it today. So it's not likely that we will a feature like #177 today.

However, you can of course implement the dispatch yourself:

// A bit of glue code, to make this example runnable on its own.

class Colors {
  static const dynamic yellow = 1;
}

class Widget {}

class Center implements Widget {
  Widget? child;
  Center({this.child});
}

class Container implements Widget {
  Widget? child;
  Container({this.child, width, height, color});
}

void runApp(_) {}

// Example code, adjusted to have a dispatcher.

void main() {
  Widget widget = Center(
    child: Container(
      width: 50,
      height: 50,
      color: Colors.yellow,
    ),
  );
  widget.foo();
  runApp(widget);
}

extension WidgetExtension on Widget {
  void foo() {
    final self = this;
    switch (self) {
      case Container():
        self.containerFoo();
      case Center():
        self.centerFoo();
      case Widget():
        self.widgetFoo();
      /*the default is no-op*/
    }
  }

  void widgetFoo() {
    print("Widget.foo");
  }
}

extension CenterWidgetExtension on Center {
  void foo() => centerFoo();
  void centerFoo() {
    print("Center.foo");
    child?.foo();
  }
}

extension ContainerWidgetExtension on Container {
  void foo() => containerFoo();
  void containerFoo() {
    print("Container.foo");
    child?.foo();
  }
}

The idea is that foo is a dispatcher method: It selects the correct implementation of "fooing" and then calls it using the static type which is obtained by promoting self.

You can write specialized versions of the dispatcher method, like CenterWidgetExtension.foo. They can be faster, because they have fewer possible types to resolve. In particular, a foo in a leaf class can just call directly. You can also ignore these specialized dispatcher methods and rely on Widget.foo in all cases.

The only remaining part is to write the implementations (centerFoo and the like). They have names that reflect their type-specific nature: We call somethingFoo when we know that this is the exact implementation we wish to run with the given receiver.


That said, I'll close this issue because the proposal is already covered by the material in #177.

@eernstg eernstg closed this as completed Sep 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
request Requests to resolve a particular developer problem
Projects
None yet
Development

No branches or pull requests

2 participants