-
Notifications
You must be signed in to change notification settings - Fork 214
Asynchronous Constructors #782
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
Comments
As far as I can understand it, the main benefit is the "super" constructor. It shouldn't be too much of an issue if the class has an class Base {
@protected
Future<void> init() {...}
}
class Subclass extends Base {
@override
Future<void> init() async {
await super.init();
// ...
}
} As far I as know, no other language has such syntax. So I'm not sure that newcomers would necessarily stop having to go on StackOverflow for such thing. |
This, to me, is the tricky part of this feature. As you note, unlike using Given that potential source of confusion, and the possible implementation complexity of chaining to generative superclass constructors asynchronously, my hunch is that this feature doesn't carry its weight. |
There is also the option of allowing you to write return types on constructors. If that is allowed, then it might also be possible to write a For generative constructors, it would still require the body to be async and implicitly wrap the created object in a future, because there is no None of this is pretty. I sortof like the idea of writing async int foo(int x) => await asyncOp(x); instead of Future<int> foo(int x) async => await asyncOp(x); It would likely reduce the number of accidental void foo() async { ... } which should have returned |
I have this use case where I want to fetch parts of config from my back end because the client wants to be able to change those parameters from their admin panel. The static method workaround is hacky at best. I agree that it would mean a change in the API of the language. But at least factory constructors could be allowed ;) |
Just want to point out that a benefit of async constructors is the elimination of runtime null checks. Currently, if your class has members that need expensive initialization, you have to make them nullable or late, as the constructor must return before they can be initialized. But with an async constructor, you could have a non-nullable member initialized, say, from a file, and the compiler would know that no instance of the object could exist until the Future returned by the constructor completes. |
@lcrocker If you don't write |
Insert usual grumblings about generic classes and class type parameter scope here. |
@munificent Well, philosophical, if you consider it an entirely philosophical issue where the type arguments go 😁. So, good point. Actually, we could allow you to write Then it's async int foo() => await bar() + await baz(); instead of Future<int> foo() async => await bar() + await baz(); If we had done that from the start, it would probably have been nice. Doing it now is going to be very confusing when the two styles mix. |
Seeing as both cases have the
I see the logic, but at the same time, I don't see anything inherently wrong or confusing with: class MyClass<T extends num> {
final T value1;
final T value2;
T _sumCache;
MyClass.fromFutures(FutureOr<T> value1, FutureOr<T> value2) async
: value1 = await value1, value2 = await value2 {
_sumCache = value1 + value2 + await somethingMore;
}
} |
Uh oh!
There was an error while loading. Please reload this page.
Users, especially new users, keep running into situations where they would like to create objects where part of the initialziation is asynchronous. They then ask for asynchronous constructors. The answer has, so far, been: Use a static factory function instead.
(dart-lang/sdk#23115, https://stackoverflow.com/questions/38933801/calling-an-async-method-from-component-constructor-in-dart, )
However, there isn't anything inherently impossible about asynchronous constructors.
Generative constructors
Consider the following:
The could define an asynchronous generative constructor. It can be redirecting only if it redirects to another asynchronous generative constructor.
Such a constructor has an implicit return type of
Future<MyClass<T>>
, and it allows usingawait
in both the initializer list and the constructor body. Theasync
is written up front because it modifies both the implicit return type and the initializer list, not just the body as for normalasync
functions.It can only be used as the
super
-constructor of another asynchronous generative constructor.As usual, the instance is not available to anyone before the body starts running, and at that point the object state is sound. You can leak the object if you want to, but if not, the caller only gets it when the body completes and the returned future is completed with that instance.
Factory constructors
The same way, we can introduce
async factory MyClass(...)
for an asynchronous factory constructor. It can either redirect to another async constructor or it can have a body which can then userawait
.The real question here is whether it's worth doing since a static factory function works. It has to be backed by a generative constructor, though, which makes it more work to implement than if you could combine everything into just the constructor.
It is a recurring issue for new users, and as such a stumbling block. It's typically solved when the user goes to stackoverflow or our forums, but it's still a negative first/early impression.
The text was updated successfully, but these errors were encountered: