Dart 2 Breaking Change Proposal: Disallow void returns from dynamic functions

139 views
Skip to first unread message

Leaf Petersen

unread,
Feb 21, 2018, 6:57:33 PM2/21/18
to Dart Misc
TLDR: We are soliciting feedback on the proposal to disallow return a `void` typed value from a function whose return type is not `void`.

The original Dart 2 proposal for the treatment of `void` attempted to prevent `void` typed values from being accidentally used.  See here for details on the proposal: https://github.com/dart-lang/sdk/issues/30597 .  When we prototyped this proposal, we felt that some of the proposed restrictions were too intrusive.  We recently landed a subset of these restrictions (announced on flutter-dev here: https://groups.google.com/forum/#!topic/flutter-dev/scnh7SfYa_o).  We are proposing to add one additional restriction, based on our observation that fixing code broken by the change is relatively benign, and that it has essentially no impact on flutter framework code.

What is the proposed change?

In Dart 1, it was legal to return a `void` typed value from a function with return type `dynamic`.  This is occasionally done implicitly (where the return type is left off the function) and only very infrequently done explicitly.

```dart
void returnsVoid() {}

// Occasionally seen
implicitDynamic() => returnsVoid();

// Rare
dynamic explicitDynamic() => returnsVoid();
```

We are proposing to make both of these uses an error, and are soliciting feedback from the community about the impact and desirability of these changes.

What should I do?

If you are opposed to this change, either because you feel it's a bad change, or because you feel that it will break too much of your existing code, please provide feedback here, on the issue linked above, or to me directly.

What should I expect to happen next?

If the sense of the community is that this change is worthwhile, we will send a breaking change announcement and land the new restrictions.  If the overall sense is that catching these issues is not worth the breakage in existing code, we will abandon this proposal.

Please feel free to reach out to me with questions or feedback.

thanks,
-leaf

Anatoly Pulyaevskiy

unread,
Feb 21, 2018, 7:08:44 PM2/21/18
to mi...@dartlang.org
I have a feeling it might break a lot of code but as long as void => void scenario still valid I think it's a good change.
By void => void I mean:

void returnsVoid() {}
void alsoReturnsVoid() => returnsVoid();

Would be interesting to see if (how often) I'm using dynamic => void in my code.
Wondering if there is a lint (or flag) I can use currently in 2.0.0-dev versions to check this?

--
For other discussions, see https://groups.google.com/a/dartlang.org/
 
For HOWTO questions, visit http://stackoverflow.com/tags/dart
 
To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+uns...@dartlang.org.

Istvan Soos

unread,
Feb 22, 2018, 3:23:28 AM2/22/18
to General Dart Discussion
Is there a language or tooling benefit of making this an error instead
of a linter hint (that is optional)?

The `implicitDynamic() => returnsVoid();` format is usually a
one-liner, while putting braces around it pushes it to three lines,
without much visible benefits otherwise. The effect is more
unfavourable when we are passing in a function closure (e.g.
Iterable.forEach).

It would be sad to lose the compact code without much upside.

Cheers,
Istvan

Jakob Roland Andersen

unread,
Feb 22, 2018, 4:07:03 AM2/22/18
to mi...@dartlang.org
I think you just need to add an explicit 'void' type:

void nowExplicitlyVoid() => returnsVoid();

should be fine. Without the type, it's implicitly dynamic, and you can't (in the proposal) return void from a dynamic function.

Florian Loitsch

unread,
Feb 22, 2018, 5:32:17 AM2/22/18
to mi...@dartlang.org
Most commonly when I don't write a type, it is because the function is `void`. In that case writing a type is useless. No correct program would ever behave differently with the `void` type.
As such, to me an implicit `dynamic` return type should thus allow everything an explicit `void` allows.

Any advantage in disallowing it at the language level instead of as a linter (where most people who care already require to write return types everywhere...)?.

tatumizer-v0.2

unread,
Feb 22, 2018, 8:34:35 AM2/22/18
to Dart Misc
The idea to treat undeclared return type as 'dynamic' in function signatures was OK for dart 1 But if the language was designed today (without dart 1 legacy), I don't think this decision would be considered sensible.
What if dart 2 starts treating omitted return type as void by default? Yes, it will break some code, but compiler will flag all errors, and the fix, in most cases, is trivial

From another perspective: how common is it to REALLY return something from such functions? 
My unscientific guess is that in majority of cases, omitted return type really means 'void'. And if this is the case, the choice of 'default return type' should follow 'most statistically likely' scenario, that's what 'default' is all about.
  

Leaf Petersen

unread,
Feb 22, 2018, 8:16:53 PM2/22/18
to General Dart Discussion
On Thu, Feb 22, 2018 at 12:23 AM, Istvan Soos <istva...@gmail.com> wrote:
Is there a language or tooling benefit of making this an error instead
of a linter hint (that is optional)?

Yes, this is a good question.  I think it just comes down to whether this is something that is considered broadly valuable enough that it should be part of the language, or just a hint.  
 
The `implicitDynamic() => returnsVoid();` format is usually a
one-liner, while putting braces around it pushes it to three lines,
without much visible benefits otherwise. The effect is more
unfavourable when we are passing in a function closure (e.g.
Iterable.forEach).

Note that for closures, we will infer `void` as the return type.  So `.forEach((a) => returnsVoid())` should be fine.

It would be sad to lose the compact code without much upside.

Noted.  Thanks for the feedback.

-leaf

Patrice Chalin

unread,
Feb 23, 2018, 6:30:07 AM2/23/18
to Dart Misc
On Thursday, February 22, 2018 at 8:16:53 PM UTC-5, Leaf Petersen wrote:
Yes, this is a good question.  I think it just comes down to whether this is something that is considered broadly valuable enough that it should be part of the language, or just a hint.  

I share Istvan's concern: if there isn't strong evidence that this will help flag real problems, w/o introducing a lot of false negatives, then I'd vote leave such a check to the linter.

IMHO, it is better to avoid one-off rules and keep the core language semantics as simple as possible because, as you know, that translates into simpler tooling, and a language that is easier to understand by its users.

I believe that currently, dynamic is meant to be a placeholder for _any_ type, including void. In Dart 1, void is equivalent to the unit type Null, since Dart 1 (like JS) has  _every_ function return a value, even a void function. Will this still hold true in Dart 2+? If not, then void could be (re-)defined to be the empty type, and an explicit dynamic could mean "any non-empty type".

Erik Ernst

unread,
Feb 23, 2018, 7:33:29 AM2/23/18
to Dart Misc
On Fri, Feb 23, 2018 at 12:30 PM, Patrice Chalin <pch...@gmail.com> wrote:
On Thursday, February 22, 2018 at 8:16:53 PM UTC-5, Leaf Petersen wrote:
Yes, this is a good question.  I think it just comes down to whether this is something that is considered broadly valuable enough that it should be part of the language, or just a hint.  

I share Istvan's concern: if there isn't strong evidence that this will help flag real problems, w/o introducing a lot of false negatives, then I'd vote leave such a check to the linter.

IMHO, it is better to avoid one-off rules and keep the core language semantics as simple as possible because, as you know, that translates into simpler tooling, and a language that is easier to understand by its users.

The simple rule is "values of type `void` are discarded". One exception was added, to cover situations where the given type annotations are misleading (for historic reasons or whatever): an explicit cast.

The proposals where the desirably concise `foo(...) => voidFunc(...);` functions get the return type `void` would enable us to keep this simple model.

(I hope, but I do not know for sure, that this can be achieved without introducing any significant complications to top-level inference: it would only apply to "simple" situations, e.g., arrow functions where the body is an invocation of a function whose return type is specified explicitly.)

In contrast, assuming that those concise functions have return type `dynamic`, I think it adds extra complexity to the language if we allow these void-typed values to be returned. It's also rather error-prone: we're silently transforming "don't use this value" to "you can use this value in _every_ way you want", based on a missing declaration.

I believe that currently, dynamic is meant to be a placeholder for _any_ type, including void. In Dart 1, void is equivalent to the unit type Null, since Dart 1 (like JS) has  _every_ function return a value, even a void function. Will this still hold true in Dart 2+? If not, then void could be (re-)defined to be the empty type, and an explicit dynamic could mean "any non-empty type".

--
For other discussions, see https://groups.google.com/a/dartlang.org/
 
For HOWTO questions, visit http://stackoverflow.com/tags/dart
 
To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+uns...@dartlang.org.

--
Erik Ernst  -  Google Danmark ApS
Skt Petri Passage 5, 2 sal, 1165 København K, Denmark
CVR no. 28866984

Reply all
Reply to author
Forward
0 new messages