Skip to content

Meta : Add lint for async intialization method #59196

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
CodingSoot opened this issue Jun 24, 2023 · 3 comments
Closed

Meta : Add lint for async intialization method #59196

CodingSoot opened this issue Jun 24, 2023 · 3 comments
Labels
devexp-linter Issues with the analyzer's support for the linter package legacy-area-analyzer Use area-devexp instead.

Comments

@CodingSoot
Copy link

CodingSoot commented Jun 24, 2023

Usually, when you need to construct a class in an asynchronous way, you use a static method:

class A {
  A._(this.param);

  final String param;

  static Future<A> create() async {
    final param = await MyService.getParam();

    return A._(param);
  }
}

// Usage : 
final a = await A.create();

This is not ideal, because :

  • Static methods can't be unnamed, so you can't do final a = await A();
  • Static methods don't preserve generic type information (so if you have generics, you need to forward them in a verbose way). This can be very troublesome if you have many type parameters with their upper bounds.
      class A<T1 extends MyClass, T2 extends Other, T3> {
         static Future<A<T1,T2,T3>> create<T1 extends MyClass, T2 extends Other, T3> async { // ...
      }

An alternative would be to have an init method :

class B {
  B();

  late final String param;

  Future<void> init() async {
    final param = await MyService.getParam();
    this.param = param;
  }
}

// Usage : 
final b = B();
await b.init();

Alternatively, the init method could be returning a newly fully initialized instance (This can be helpful in some specific implementations where the initialized instance MUST be a newly created one) :

class C {
  C();

  late final String param;

  Future<C> init() async {
    final param = await MyService.getParam();
    return C()..param = param;
  }
}

// Usage : (Notice how it's a one-liner now)
final c = await C().init();

The problem with having an initialization method is that if you forget to call it, you get a runtime error.

It would be great if we could annotate the init method with something like @initMethod, and whenever you call the constructor / factory constructor, you get a warning reminding you to call the init method.

@lrhn
Copy link
Member

lrhn commented Jun 25, 2023

I highly recommend using the static async factory method approach, even if it requires more typing. It's safer in every way.

(If anything, I'd want a lint warning against using init functions, but there are places where they make sense too.)

@CodingSoot
Copy link
Author

I understand where you're coming from. However, I feel like async instantiation is a very common pattern and deserves an easier syntax than static async methods (especially when there are generics).

Since there seems to be no plan to add support for async factory constructors (see dart-lang/language#782), I thought maybe this could be solved by adding a new annotation to the meta package that would basically make using init methods safe.

@srawlins srawlins transferred this issue from dart-lang/sdk Jun 30, 2023
@bwilkerson
Copy link
Member

I'm going to close this as not planned because I don't think we want to encourage this style.

@bwilkerson bwilkerson closed this as not planned Won't fix, can't repro, duplicate, stale Jul 10, 2023
@devoncarew devoncarew added devexp-linter Issues with the analyzer's support for the linter package legacy-area-analyzer Use area-devexp instead. labels Nov 19, 2024
@devoncarew devoncarew transferred this issue from dart-archive/linter Nov 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
devexp-linter Issues with the analyzer's support for the linter package legacy-area-analyzer Use area-devexp instead.
Projects
None yet
Development

No branches or pull requests

4 participants