The language will change to allow void as a type argument in generics (and as a type annotation in general).
This comes up in cases like:
Future<void>. Today, code either uses Future, which doesn't give you great static checking of the result, or Future<Null>, which is kind of unfamiliar to most users.AstVisitor<void>.We also allow void to be the type annotation for locals, parameters, fields, ...
In Dart 1, void should simply be treated like Object, except as a return type for function types (where the old behavior should be kept).
In strong mode, an additional "voidness" rule will disallow assignments from void to Object when the assignment is statically visible. We will update the bug when we have a document ready.
A void function can actually return anything (or more precisely: a function assignable to a function type with void return type, can return anything because of the way "more specific" is defined on functions).
That has led to errors where someone does
void foo() => delegate.foo();
but the delegate type's foo overrides the expected type with a function returning non-void and returns a non-null value. In checked mode that's an error.
The fix for that will likely be to allow anything to be returned by a void function. That makes void act like Object (and at runtime, it will likely _be_ Object) except that you can't _use_ a value with static type void for anything.
Status update: we need to do #27727 for 1.50, but can implement this issue at a later point.
Another use case could be that raw generic types could implicitly have void as their generic type parameter if the user has disabled implicit dynamic.
@dskloetg this is tackled already. See #27727 mentioned by floitschG above and #17518, #26275
@zoechi I'm not sure how that is related.
I mean the following. Today when I write Future (without type parameter), it's interpreted as Future<dynamic>. With --no-implicit-dynamic it could be interpreted as Future<void> instead.
@dskloetg Currently you can use Future<Null> to get what you expect from Future<void>. AFAIK the work done in the linked issues, is to allow void where currently Null is required.
<Null> is a hack (e.g. it has .toString()). I wouldn't argue to enable a hack with --no-implicit-dynamic.
I'm talking about implicitly having <void> when you don't specify it.
The STRONG_MODE_INVALID_CAST_FUNCTION_EXPR is ignored in ~24 places in the Flutter code base. This seems important to address.
I've run into two issues relating to this with code like the following:
import 'dart:async';
void foo(x) {}
void main() {
Future.wait([
new Future.value().then(foo),
new Future<bool>.value(false)
]);
}
On 1.22, this produces the error The element type 'Future<bool>' can't be assigned to the list type 'Future<void>'. After talking to @leafpetersen, it seems like there are two issues here:
Future<bool> should be assignable to Future<void>.The LUB is a continuing problem. It's not very good at handling generic classes, so the LUB of Future<void> and Future<bool> is ... Object.
The LUB in the specification is based on super-interfaces, not super-types, and the only super-interface of Future<bool> is Object. Even if Future<void> is a super-type of Future<bool>, LUB(Future<void>, Future<bool>) is still Object.
We need a better LUB, even more so now that it's used in inference too.
I updated the issue description to reflect the current status.
Do we have tests for this feature?
Not yet. I'll be writing an informal spec, and I expect that we can obtain tests from multiple contributors including the language team, as we've done before.
This is a subset of the functionality described in Generalized void meta issue #30176
Most helpful comment
A
voidfunction can actually return anything (or more precisely: a function assignable to a function type withvoidreturn type, can return anything because of the way "more specific" is defined on functions).That has led to errors where someone does
but the
delegatetype'sfoooverrides the expected type with a function returning non-void and returns a non-null value. In checked mode that's an error.The fix for that will likely be to allow anything to be returned by a
voidfunction. That makesvoidact likeObject(and at runtime, it will likely _be_Object) except that you can't _use_ a value with static typevoidfor anything.