{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/corefx/issues/2349","labels_url":"https://api.github.com/repos/dotnet/corefx/issues/2349/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/corefx/issues/2349/comments","events_url":"https://api.github.com/repos/dotnet/corefx/issues/2349/events","html_url":"https://github.com/dotnet/corefx/issues/2349","id":94856537,"number":2349,"title":"Short-circuit when possible during Enumerable methods.","user":{"login":"hackcraft","id":1253369,"avatar_url":"https://avatars.githubusercontent.com/u/1253369?v=3","gravatar_id":"","url":"https://api.github.com/users/hackcraft","html_url":"https://github.com/hackcraft","followers_url":"https://api.github.com/users/hackcraft/followers","following_url":"https://api.github.com/users/hackcraft/following{/other_user}","gists_url":"https://api.github.com/users/hackcraft/gists{/gist_id}","starred_url":"https://api.github.com/users/hackcraft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hackcraft/subscriptions","organizations_url":"https://api.github.com/users/hackcraft/orgs","repos_url":"https://api.github.com/users/hackcraft/repos","events_url":"https://api.github.com/users/hackcraft/events{/privacy}","received_events_url":"https://api.github.com/users/hackcraft/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":{"login":"VSadov","id":8218165,"avatar_url":"https://avatars.githubusercontent.com/u/8218165?v=3","gravatar_id":"","url":"https://api.github.com/users/VSadov","html_url":"https://github.com/VSadov","followers_url":"https://api.github.com/users/VSadov/followers","following_url":"https://api.github.com/users/VSadov/following{/other_user}","gists_url":"https://api.github.com/users/VSadov/gists{/gist_id}","starred_url":"https://api.github.com/users/VSadov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/VSadov/subscriptions","organizations_url":"https://api.github.com/users/VSadov/orgs","repos_url":"https://api.github.com/users/VSadov/repos","events_url":"https://api.github.com/users/VSadov/events{/privacy}","received_events_url":"https://api.github.com/users/VSadov/received_events","type":"User","site_admin":false},"milestone":null,"comments":1,"created_at":"2015-07-14T02:57:27Z","updated_at":"2015-07-15T13:25:11Z","closed_at":null,"body":"As mentioned at #2237 and #2238, there are methods of `Enumerable` that can benefit from short-circuiting.\r\n\r\nNow, logically a great many could such as e.g. `Max(this IEnumerable<int>)` testing for `int.MaxValue`, but that would require an additional check that would penalise all sequences that didn't have that value.\r\n\r\nHowever:\r\n\r\n1. The logical behaviour of `Single` and `SingleOrDefault` is \"look for a match, then check there isn't another\" (just like `Where(pred).Single()`). Following that rather than keeping count removes work from non-error paths as well as shortening error paths.\r\n\r\n2. `Min`/`MinOrDefault` already have to check for `NaN` explicitly, so they don't suffer from any further work being done.\r\n\r\n3. Adding a check for `IList<T>` sources to `Last`/`LastOrDefault` adds only a single check to the entire operation. The search can then proceed in reverse order and break on the first match.\r\n\r\nThese changes all affect existing behaviour, in that if either the enumerable expected to be consumed, or they were used with a predicate that had a side-effect, that behaviour would now change.\r\n\r\nOn the one hand, any change to observed behaviour bar pure performance increase is bad.\r\n\r\nOn the other hand:\r\n\r\n1. If you have side-effects in a `Func` you are going to have problems elsewhere, particularly elsewhere in Linq which tends to short-circuit where it can.\r\n2. If you depend on an enumerable being consumed you are going to have problems elsewhere, , particularly elsewhere in Linq which tends to short-circuit where it can.\r\n3. The idea of Linq being side-effect free is supported not just in the documentation, but as a justification for the lack of a `ForEach` outside of cases (parallel, asynchronous) where some other feature is added (eh, being parallel or asynchronous).\r\n4. The current behaviour would be confusing to someone depending on side-effects anyway: Why does `Single(pred)` behave differently to `Where(pred).Single()`?\r\n5. The behaviour of `Single` can exasperate bugs. (I had a case where certain values would throw a sequence into an incorrect repetition. Rather than `Single()` throwing at this bug, it hung).\r\n\r\nSide-benefit: I noticed when working on this that not only do the current `Min(IEnumerable<double>)` etc. fail to take the short-circuit opportunity if it encounters a `NaN`, but they can actually perform much slower on a sequence with a `NaN` in the middle than one without, presumably due to branch mis-prediction. It's reasonable to believe that there may be other branch mis-prediction cases that such short-circuiting would help remove."},"comment":{"url":"https://api.github.com/repos/dotnet/corefx/issues/comments/121615969","html_url":"https://github.com/dotnet/corefx/issues/2349#issuecomment-121615969","issue_url":"https://api.github.com/repos/dotnet/corefx/issues/2349","id":121615969,"user":{"login":"stephentoub","id":2642209,"avatar_url":"https://avatars.githubusercontent.com/u/2642209?v=3","gravatar_id":"","url":"https://api.github.com/users/stephentoub","html_url":"https://github.com/stephentoub","followers_url":"https://api.github.com/users/stephentoub/followers","following_url":"https://api.github.com/users/stephentoub/following{/other_user}","gists_url":"https://api.github.com/users/stephentoub/gists{/gist_id}","starred_url":"https://api.github.com/users/stephentoub/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stephentoub/subscriptions","organizations_url":"https://api.github.com/users/stephentoub/orgs","repos_url":"https://api.github.com/users/stephentoub/repos","events_url":"https://api.github.com/users/stephentoub/events{/privacy}","received_events_url":"https://api.github.com/users/stephentoub/received_events","type":"User","site_admin":false},"created_at":"2015-07-15T13:25:11Z","updated_at":"2015-07-15T13:25:11Z","body":"@VSadov, @jaredpar, @terrajobst, what's our tolerance for this level of change?  Makes sense from a perf perspective to short-circuit whenever possible in LINQ... the question would primarily be one of compat concerns with folks relying on existing side-effects of executing queries."}}