Why only one overload throws this exception?
Little update: I understand that there was a design decision made by framework developers. The question is really why that decision has been made, is there a related design pattern or whatever? Because if I was designing that I’d return default(TSource). What is wrong with such approach?
The one overload that throws the exception takes arguments of type
IEnumerable<TSource>(this) andFunc<TSource, TSource, TSource>. It starts with the first value and accumulates from there. Without a first value (ifsourceis empty), there’s no way for the function to know what to return.The other two overloads accept an argument of type
TAccumulateto act as the seed. Even ifsourceis empty in this case, the function can simply return the seed value.Update: You ask why the decision was made not to simply use
default(T)in the case of an empty sequence. The answer doesn’t boil down to any specific pattern or known idiom, but rather simply to what is (in my opinion) the sensible choice in terms of API design. The point ofAggregateis to make it easy for developers to implement calculations for their own domain-specific problems, without making assumptions about the semantics of those calculations.To use
default(T)in the case of an empty sequence would be making not one but two pretty big assumptions:default(T)As a trivial counter-example to the first assumption, let’s say I use
Aggregateto compute the mode of a sequence of integers. This should give me the value occurring most frequently in the sequence, so a result of zero would simply be false (since the value0never occurs in an empty sequence).As a counter-example to the second, suppose I take the product of reciprocals of a sequence of positive integers:
In this case the result would actually approach zero as the sequence gets larger, so a default value of zero would, again, be completely misleading.