Closed eernstg closed 4 years ago
I have no problem allowing Never
. I'd want the analyzer to give a warning because it is, as you say, useless, but it's a complication for the language to disallow it.
If you end up writing extension E on Never
, you'll probably realize your issue when you try to test it. If not, I'll have to assume that it's deliberate (not that I can imagine the reason, but that's rather the point: The language should not be restricted merely because I can't imagine a use).
Any code using the extension, E(neverAnything()).foo()
will have the foo
call being dead code. If we warn about dead code, then that's covered.
Then we avoid getting into weird discussion about whether extension F<T> on T { ... foo...}
is allowed when you can write F(throw 0).foo
. There is nothing inherently wrong with extension E on Never {}
which isn't wrong with class C { Never self; C(this.self) }
too. That class is uninstantiable, but we won't disallow it. I see extensions on Never
the same way. It's fairly easy, almost unavoidable, to catch the problem if it happens by accident.
I'm also not especially motivated to forbid this. extension E on Never { // static methods }
actually seems like possibly the best workaround for the lack of namespaces in Dart. More generally, would we forbid extension E<T extends Never> on T
? etc.
OK, what I hear is broad support for allowing all of them, and then we can address "you probably didn't mean this" as needed, separately, using dead code detection and such.
About the philosophers, dining or not, we have lots of ways to match the same types:
// ... some examples already given, but any top type will do:
extension on FutureOr<FutureOr<Object?>> {}
// ... and any type variable bounded by a top type:
extension E<X extends void?> on X {}
// ... and we can put these types into other types to get ambiguity there:
extension on List<dynamic> {}
extension on List<void?> {}
// ... etc.
We have a lot of machinery which is specifically dealing with ambiguities arising from having several matching extensions for the same call site. We discussed in great detail how to disambiguate in these situations, so we shouldn't need to reconsider.
life would be boring
Can't have that, we all know it's good to live in interesting times. ;-)
Closing: I'll conclude that we allow all valid Dart types to be an on
type of an extension. This matches the following, which is already in the extension-method feature specification:
The type can be any valid Dart type, including a single type variable.
The feature specification of static extension methods mentions that
which prevents
e.m
from invoking an extension member whene
has one of these special types.But I do not see any rules preventing the special types as the
on
type of an extension:I think it is not necessary to consider other types (
FutureOr
comes to mind, of course), because they are allowed, and it does make sense.But
Never
could be made an error. It is impossible to invoke an extension method on a receiver of typeNever
, because it is an error to access any member in any way on such a receiver. So that's not likely to be useful, and anon
type ofNever
essentially enforces that the receiver type isNever
(the only other possibilities areX extends Never
and similar corner cases).The type
void
could be used as anon
type of an extension, and it could make sense: If the extension is designed to have side-effects on global state only, it would not need to accessthis
, and it might be useful to use theon
typevoid
to document that fact.Similarly, the type
dynamic
could be used as anon
type in order to usethis
dynamically in the extension members.So we may or may not wish to allow
void
anddynamic
ason
types, but we probably don't want to allowNever
, given that all the non-static members are dead code. Note that #455 contains discussions aboutNever
in many other contexts than extensions, so we should have this connection in mind in order to keep the rules consistent.@lrhn, @munificent, @leafpetersen, WDYT?