Re: [analyzer-discuss] Functions including return statements with and without value

111 views
Skip to first unread message

Brian Wilkerson

unread,
Mar 8, 2018, 10:36:50 AM3/8/18
to General Dart Discussion
Moved discussion to 'mi...@dartlang.org'.

On Wed, Mar 7, 2018 at 11:24 PM, Anatoly Pulyaevskiy <anatoly.p...@gmail.com> wrote:
Currently if I write a function like below I'll get analyzer warning:

myFunc() {
  if (isSomething) return;
  return "some value";
}

Analyzer warning: Functions can't include return statements both with and without values.

As we know in JS this is not an issue and sometimes is even used as a feature. Which is the case with Firebase Database JS client.

As I'm working on a Dart package which wraps JS client I needed to come up with a way to get this working.
So I did this:

  Function _createTransactionHandler<T>(TransactionHandler<T> handler) {
    // This is a workaround for analyzer which complains if a function contains
    // return statements with and without value.
    void undefined() {}

    // Firebase requires us to return JS `undefined` to indicate we want 
    // to abort the transaction.
    return (currentData) {
      final data = dartify(currentData);
      final result = handler(data);
      if (result._abort) return undefined(); // workaround continues...
      return jsify(result.data);
    };
  }

Which works (with latest Dart2 SDK, 2.0.0-dev.32.0). But I was wondering if there is any plans in Dart2 to statically restrict this kind of usage?

My gut feeling says that since `void` in Dart2 is more like a value of special type (we can use it in generics like Future<void>) then my workaround should be statically allowed, but I just wanted to confirm it with the team.

Thanks!

--
You received this message because you are subscribed to the Google Groups "Dart Analyzer Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to analyzer-discuss+unsubscribe@dartlang.org.
Visit this group at https://groups.google.com/a/dartlang.org/group/analyzer-discuss/.

Matan Lurey

unread,
Mar 8, 2018, 10:39:32 AM3/8/18
to mi...@dartlang.org

To unsubscribe from this group and stop receiving emails from it, send an email to analyzer-discu...@dartlang.org.

--
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.

tatumizer-v0.2

unread,
Mar 8, 2018, 11:30:59 AM3/8/18
to Dart Misc
Can dart 
return (void)0
?


Anatoly Pulyaevskiy

unread,
Mar 8, 2018, 1:01:06 PM3/8/18
to Dart Misc
Thanks, subscribed. There is one more linked to it (https://github.com/dart-lang/sdk/issues/32177) where ) left a comment with this use case.

I also found an alternative way to achieve what I needed. Didn't think I can create JS binding for undefined, but it works actually in both ddc and dart2js:

  @JS()
  external get undefined;

  
Function _createTransactionHandler<T>(TransactionHandler<T>
 handler) {
    
return (currentData) {
      final data = dartify(currentData);
      final result = handler
(data);
      if (result._abort) return undefined;
      return jsify(result.data);
    };
  }

I'll probably switch to this version as it seems more reliable.

Anatoly Pulyaevskiy

unread,
Mar 8, 2018, 1:04:45 PM3/8/18
to Dart Misc
Sorry about formatting issues, here is plain-text version of the same code snippet:

Lasse R.H. Nielsen

unread,
May 9, 2018, 4:29:25 AM5/9/18
to mi...@dartlang.org
On Thu, Mar 8, 2018 at 7:04 PM Anatoly Pulyaevskiy <anatoly.p...@gmail.com> wrote:
Sorry about formatting issues, here is plain-text version of the same code snippet:

  @JS()
  external get undefined;

  Function _createTransactionHandler<T>(TransactionHandler<T> handler) {
    return (currentData) {
      final data = dartify(currentData);
      final result = handler(data);
      if (result._abort) return undefined;
      return jsify(result.data);
    };
  }

I'm not sure why this is better than just using: return null;

What you have here is a method declared as returning a Function. You can't return a void expression inside that, and you can't use a return statement with no expression.
You can only return void expressions from funtions with return type void (or async functions with return type Future<void>), and you can only use return with no expression where you can return void expressions. We might not have this nailed down on all implementations yet, but that's the design.

Every return in this function must return something that can be assigned to Function, which is any function value ... or null. If your undefined value isn't one of those, this should give you a runtime error, so luckily it is, because it is actually null.

In more detail, in the return undefined; statement, "undefined" has type dynamic, so you get a runtime down-cast from dynamic to Function which should check that the actual value (which you have made the JS undefined value) is assignable to Function. It is, because JS compiled Dart treats undefined as the Dart null value, so you might as well just return null directly.

/L


--
Lasse R.H. Nielsen - l...@google.com  
'Faith without judgement merely degrades the spirit divine'
Google Denmark ApS - Frederiksborggade 20B, 1 sal - 1360 København K - Denmark - CVR nr. 28 86 69 84

Anatoly Pulyaevskiy

unread,
May 9, 2018, 12:15:02 PM5/9/18
to mi...@dartlang.org
Lasse,

The way I understand it is that this issue is more JS-specific rather than Dart-specific.

In JS null and undefined are two different things, which means null == undefined would return false.

I can return null from my function but the JS code that invokes it doesn’t care about null, it only checks for undefined, so I needed a way to do exactly what JS code expects.

Basically I need a function which only returns Function or undefined, and never null.

In Dart there is no equivalent for undefined, as far as I know, void is probably close but not exactly. So that’s why I had to declare binding for undefined.

I should probably change return type to dynamic to not confuse type checking system.

Hope this makes sense.

Best,
Anatoly
--
For more ways to connect visit https://www.dartlang.org/community

---
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.

Anatoly Pulyaevskiy

unread,
May 9, 2018, 12:56:39 PM5/9/18
to mi...@dartlang.org
Oh, just looked at my own example again. The problem is not in the _createTransactionHandler itself (which actually always returns Function) but in the closure created by this method.

That closure must return an object representing the value, and null is a valid value in this case. To abort the transaction it must return undefined (in Dart semantics it must not return anything or in other words return void).

Lasse R.H. Nielsen

unread,
May 13, 2018, 5:42:33 AM5/13/18
to mi...@dartlang.org
On Wed, May 9, 2018 at 6:56 PM Anatoly Pulyaevskiy <anatoly.p...@gmail.com> wrote:
Oh, just looked at my own example again. The problem is not in the _createTransactionHandler itself (which actually always returns Function) but in the closure created by this method.

That closure must return an object representing the value, and null is a valid value in this case. To abort the transaction it must return undefined (in Dart semantics it must not return anything or in other words return void).

That's not actually Dart semantics. Dart's `void` return type does not mean "don't return anything". It means "returns something you shouldn't use", which is most likely null.
In JS compiled Dart code, both JS null and JS undefined are considered the Dart null value.

If you actually need to return the JS undefined values, then explicitly returning the result of the external undefined getter is the correct thing to do. Do not depend on there being a difference between `return;` and `return null;`, that's not something the language promises, and it's not unlikely that the front-end will end up making the two indistinguishable (because they are at the Dart language level).

/L
 

Anatoly Pulyaevskiy

unread,
May 17, 2018, 8:48:52 PM5/17/18
to mi...@dartlang.org
That's not actually Dart semantics.

Sorry, I guess that's not what I was trying to say by using "semantics" here. What I meant is that there is no explicit equivalent for "undefined" in Dart and I just thought that "void" is as close as it gets (in fact it is actually treated as "undefined" when compiled to JS, as in my first attempt).

Thanks for the thorough explanation! Now it all makes more sense to me.

Reply all
Reply to author
Forward
0 new messages