Conditional member access: null isn't appropriate in a conditional

284 views
Skip to first unread message

Karan Sikka

unread,
Jun 15, 2017, 6:49:05 PM6/15/17
to Dart Misc
When you try:

if (foo?.bar) {...}

You get an error since "foo?.bar" can be null. There are two ways around this AFAICT:

if (foo?.bar == true) {...}

and

if (foo?.bar ?? false) {...}


Which of these is preferred? (Assuming foo.bar return a bool). Thanks!

Bob Nystrom

unread,
Jun 15, 2017, 7:16:08 PM6/15/17
to General Dart Discussion
I don't know if there is strong consensus across the ecosystem.

Personally, I prefer the second one because the "??" communicates clear "this operator has something to do with null", where "== true" often looks like a mistaken unnecessary check if the reader doesn't realize the left-hand side may not return a Boolean.

Cheers!

– bob

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

Samuel Rawlins

unread,
Jun 15, 2017, 7:21:00 PM6/15/17
to General Dart Discussion
Ugh, yeah I hate getting into this situation. It's just a personal preference, but I often assign straight up avoid null-aware in this situation:

if (foo != null && foo.bar) { ... }

I personally don't like the `if (foo?.bar ?? false)` because it has the worst ergonomics. It reasons fine, but it just looks like a bizarre incantation. I think its a failing of null-aware when you're forced to use two variations at one time just to use it in a conditional.

On Wed, Jun 14, 2017 at 11:02 AM, 'Karan Sikka' via Dart Misc <mi...@dartlang.org> wrote:

--

Karan Sikka

unread,
Jun 15, 2017, 11:03:37 PM6/15/17
to mi...@dartlang.org
I agree with all these opinions. Thanks! Will probably use == true. At least I wont double-take every time I see it.

Lasse R.H. Nielsen

unread,
Jun 16, 2017, 1:28:04 AM6/16/17
to mi...@dartlang.org
On Fri, Jun 16, 2017 at 5:03 AM, 'Karan Sikka' via Dart Misc <mi...@dartlang.org> wrote:
I agree with all these opinions. Thanks! Will probably use == true. At least I wont double-take every time I see it.

... but I will when I review your code. I'll think "can't you just remove that?". Then I'll spend more time examining the code until I realize that "oh, it's because it might be null as well". At that time, I've wasted more time than you would have writing it in a different way. 

My vote, if I get to vote, is firmly *against* "== true". As stated earler, it *looks* wrong. 
My personal rules for booleans include:
- Never compare to a boolean.
- Never have a boolean literal as either branch of a conditional expression.
If you violate the former, I will read your code to figure out why. If you violate the latter, I can accept it, but I'll try to rewrite it using && or ||.

I'm with Sam Rawlins on this one - his code is longer, but it is immediately readable.

The ?. operator works fine for staying inside nullable types, and ?? is a way to get out of the nullability, so
   foo?.bar ?? false
works for me on he type level, but ... it's just not as easily readable as
   foo != null && foo.bar

/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

Alexandre Ardhuin

unread,
Jun 16, 2017, 5:54:35 AM6/16/17
to General Dart Discussion
Reading https://www.dartlang.org/guides/language/language-tour#booleans :

> When Dart expects a boolean value, only the value true is treated as true.

Couldn't it be possible to make the if statement treat null as false ? Thus we could simply write `if (foo?.bar) {...}`

Alexandre

Erik Ernst

unread,
Jun 16, 2017, 6:53:15 AM6/16/17
to Dart Misc
On Fri, Jun 16, 2017 at 11:54 AM, Alexandre Ardhuin <alexandr...@gmail.com> wrote:
Reading https://www.dartlang.org/guides/language/language-tour#booleans :

> When Dart expects a boolean value, only the value true is treated as true.

Couldn't it be possible to make the if statement treat null as false ? Thus we could simply write `if (foo?.bar) {...}`

We did discuss doing exactly that in general for boolean-controlled statements, but (if it ever gets enough support to go anywhere) it would be separate from the normal statements. The conceptual justification would be that certain things should be done or repeated if "something exists, and it has a certain property", in which case it makes sense to say that `null` anywhere in an computation with several steps means "that it doesn't exist" and then we don't do it. That makes `null` falsey. But I'm pretty sure that it is never going to _replace_ the current semantics where `null` is an error.



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

tatumizer-v0.2

unread,
Jun 16, 2017, 5:09:40 PM6/16/17
to Dart Misc
While we are at it - what happened with  nullable types? It used to be the most exciting issue on this mailing list for quite a while, and then ... total silence.

Bob Nystrom

unread,
Jun 16, 2017, 5:46:33 PM6/16/17
to General Dart Discussion
On Fri, Jun 16, 2017 at 2:09 PM, tatumizer-v0.2 <tatu...@gmail.com> wrote:
While we are at it - what happened with  nullable types? It used to be the most exciting issue on this mailing list for quite a while, and then ... total silence.

Sorry, that's my fault.

I haven't been working on it lately. The Dart team has two big things going on right now:
  • Moving towards a single unified front end that supports strong mode. This lets us implement the strong mode static and runtime semantics across dev_compiler, dart2js, and the VM.

  • Doing whatever is needed to get Flutter ready as they move towards a more production-ready release.
The former is eating up much of our front-end implementation resources and the latter is keeping most of the language folks busy. That hasn't left much time for a giant feature like non-nullable types. In the meantime, I've been working on improving our type promotion rules. That's a necessary step to make non-nullable types usable, so it's still getting us closer to that goal, and it also improves code that doesn't use non-nullable types. It means instead of awkward code like:

class Point {
  final int x, y;
  bool operator ==(Object other) {
    if (other is Point) {
      return x == other.x && y == other.y;
    } else {
      return false;
    }
  }
}

You can instead do:

class Point {
  final int x, y;
  bool operator ==(Object other) {
    if (other is! Point) return false;
    return x == other.x && y == other.y;
  }
}

I hope to get back to non-nullable types soon.

Cheers!

– bob

Samuel Rawlins

unread,
Mar 14, 2018, 9:44:49 AM3/14/18
to General Dart Discussion, Alexandre Ardhuin
To loop back on this: I don't think any behavior has changed in dart2js or the VM, but Alexandre added new checks as of Dart ~2.0.0-dev.32.0. Thanks Alexandre!

  • NULL_AWARE_BEFORE_OPERATOR: "The left operand uses '?.', so its value can be null."
    For example, in `foo?.length + 1`
  • NULL_AWARE_IN_LOGICAL_OPERATOR: "The value of the '?.' operator can be 'null', which isn't appropriate as an operand of a logical operator."
    For example in `foo?.isNotEmpty && bar?.isNotEmpty` or `!foo?.isNotEmpty`
When fixing up code that now features this new Hint, I found a lot of `a && b?.c ?? false`. Does this do what you think? Maybe not! It's actually `(a && b?.c) ?? false`. Boo. Luckily both the new analyzer hints catch this, and dartfmt can highlight this when it is forced to wrap lines. For example, dartfmt will output the following:

void main() {
  var result1 =
      something.attribute.otherAttribute && somethingOtherThing?.attr?.attr ??
          false;

  var result2 = something.attribute.otherAttribute &&
      (somethingOtherThing?.attr?.attr ?? false);
}

Notice how dartfmt grouped `a && b` onto one line, breaking after `??`. A small hint. When you change the expressions with parens, for result2, dartfmt will now keep the `a ?? false` on one line, as that is one expression.
Reply all
Reply to author
Forward
0 new messages