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.
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
orElseparameter is a function, not a value
Whoops! Makes sense now (well, kinda).
I have yet to run into a case where I want
firstWhereto 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 :-)
Most helpful comment
The
orElseparameter 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 usenullas a default by calling as: