Skip to content

Eliminate prefer_void_to_null? #59309

Open
@eernstg

Description

@eernstg

Describe the issue

The lint prefer_void_to_null is probably obsolete. It is certainly possible that it has been helpful in the effort to eliminate some suboptimal usages of the type Null, but it is most likely not a good fit for the language today. I'd recommend that this lint is removed entirely.

To Reproduce

Several examples have been given where this lint emits a message, but the advice is not applicable or useful. Here is one example:

void main() {
  List<(int?, int?)> xs;
  ...
  xs = <(Null, int)>[(null, 10)]; // LINT
}

In this case it is not possible to replace the type Null by the type void, as recommended by the lint (it's a compile-time error to do that, as it should be). Also, the chosen types may be slightly odd, but they do make sense in this context.

Further discussions and examples can be found in several issues:

Finally, consider the examples given in the documentation for the lint itself (renaming the declarations because they were all named f):

// BAD:

Null f1() {}
Future<Null> f2() {}
Stream<Null> f3() {}
f4(Null x) {}

// GOOD:

void f1() {}
Future<void> f2() {}
Stream<void> f3() {}
f4(void x) {}

It is not obvious why the type Null has been used in the signature of these functions (and some of them might actually need to be updated to use Never today in order to make sense), but we should note that all of those changes would be breaking.

If f1 is called and the result is assigned to a variable of type T? for any T then it would now be a compile-time error. Similarly for f2 and f3 if the returned value is assigned to Future<T?> or Stream<T?> for any T. Finally, f4 could be an instance method which is overridden by f4(int? iq), and the change to f4(void x) {} would now break that override.

The motivation for the lint was probably that this is good breakage, because those functions should not have been declared using the type Null in the first place. However, it is not obvious to me that this kind of motivation is justified today: Is it really true that the change from Null to void is useful, and worth the breakage?

I tend to think that the spurious occurrence of null at run time used to be an issue worth fighting against, but with null safety in the type system we already know how to avoid null when it really shouldn't occur, and if nulls are allowed in any given context then every non-Object? usage of the null will be guarded by a null check.

Expected behavior

The lint should only give advice which is applicable and useful, but it seems to produce a large amount of false positives.

Additional context

Null safety has completely changed the role played by the type Null. In this new context, prefer_void_to_null does not play a constructive role in most of the situations where it used to be helpful. I don't think there is a natural and useful modification which can be used to bring this lint up to date, hence I'm suggesting that get gets removed.

Does anyone have some really compelling reasons why this lint is still useful?

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2A bug or feature request we're likely to work onarea-devexpFor issues related to the analysis server, IDE support, linter, `dart fix`, and diagnostic messages.devexp-linterIssues with the analyzer's support for the linter packagelinter-set-recommendedtype-questionA question about expected behavior or functionality

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions