Sdk: firstWhere throws when provided orElse: null if no items matched (expectation was null returned)

Created on 5 Feb 2018  路  8Comments  路  Source: dart-lang/sdk

The firstWhere docs say that if there's no matching element a StateError will be thrown unless you provide an orElse argument. However I was just caught out that if I pre-filter the list with another .where() which matches no elements, a StateError is thrown regardless of the orElse:

[1]
  .where((a) => a > 10)
  .firstWhere((a) => a == 0, orElse: null);
Bad state: No element
    at Object.wrapException (<anonymous>:611:17)
    at WhereIterable.firstWhere$2$orElse (<anonymous>:1302:17)
    at Object.main (<anonymous>:1372:54)

IMO this behaviour seems wonky (and different to other similar methods from other languages I've used) - it means chaining wheres and then a firstWhere isn't the same as putting all the conditions in the firstWhere (which seems to encourage a single firstWhere with a long set of conditions), however if that's how it's expected to be I think there should be a mention in the docs that an empty input will always throw regardless of the condition of the orElse argument.

Most helpful comment

The orElse parameter is a function, not a value. That's occasionally annoying, but also strictly more powerful than passing a single value. It also allows you to actually use null as a default by calling as:

someIterable.firstWhere(test, orElse: () => null);

All 8 comments

Oh dear, I see what's happening... orElse: null of course is the same as not passing orElse! That's a bit unfortunate... should there be some sort of undefined value? ;-)

Probably related: #7939

In C#'s LINQ there's a .FirstOrDefault, .SingleOrDefault which are used quite a bit; would something similar be considered?

The orElse parameter is a function, not a value. That's occasionally annoying, but also strictly more powerful than passing a single value. It also allows you to actually use null as a default by calling as:

someIterable.firstWhere(test, orElse: () => null);

I have yet to run into a case where I want firstWhere to throw :-/

The orElse parameter is a function, not a value

Whoops! Makes sense now (well, kinda).

I have yet to run into a case where I want firstWhere to throw :-/

I can't think of one off the top of my head, but in C#/LINQ we definitely used First() and FirstOrDefault() a fair bit (and same for Single's). FirstOrDefault was definitely more common though (and the opposite for Single because that was really used specifically to crash if something is not as expected).

@DanTup when the collection is expected to also contain null. I can imagine such cases, but I never run into one myself, so the default case "throwing" is IMHO annoying.

Sure, I'll go with it's a bad default - I just think there's a place for both and both could be made easy (like they are in C# where there are just two methods, First and FirstOrDefault). While FirstOrDefault doesn't let you customise the default value, you can easily append ?? someValue on the end (for nullables at least).

@DanTup am I right that for now firstOrDefault not exists?

@fryette I don't think so. You might be able to implement it with an extension method that just calls firstWhere with an orElse though :-)

Was this page helpful?
0 / 5 - 0 ratings