36

I have come across this code in MoreLinq, in file Batch.cs (link):

return _(); IEnumerable<TResult> _()

I read up on discards, but nevertheless I cannot make sense of the above code. When I hover above the first _ it says: "Variables captured: resultSelector, collection".

  • What do the two _() represent?
  • Since we are doing a return _();, how can the subsequent code IEnumerable<TResult> _() still be executed?
Robotronx
  • 1,728
  • 2
  • 21
  • 43

2 Answers2

34

The _() here is a call to the local function called _. Unusual, but valid.

A local function is broadly like a regular method, except that it can only be called by name (i.e. the usual way you call a method) from inside the method that declares it (as Eric points out in a comment, there are some other ways that it could be called, for example via a delegate passed out from the method), and (unless decorated static) it can pick up locals and parameters from the declaring method as state.

In this case, the intent is to perform eager parameter validation. With validation code in the iterator block, the parameters validation would be deferred until the first MoveNext() call. (i.e. it wouldn't complain about source being null until someone attempts to foreach over the data).

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Shouldn't the body always be declared? – Marco Salerno Jan 27 '20 at 08:33
  • 1
    @MarcoSalerno Yes, but I imagine the OP didn't quite paste the code exactly. – Matthew Watson Jan 27 '20 at 09:05
  • @MatthewWatson by opening the source I noticed it is there, the highlight made me blind ahah – Marco Salerno Jan 27 '20 at 09:11
  • Any pointers on "eager parameter validation"? I am having a hard time finding resources. I read up on iterator blocks, but not seeing the connection clearly. – Robotronx Jan 27 '20 at 09:34
  • 1
    @Robotron try this: https://gist.github.com/mgravell/047f7fcfd2755819b8de7c5afaaf3001 ; this difference can make it more obvious where the actual problem lies; if you pass an unvalidated sequence through a few layers before calling `foreach`, the actual point where the wrong thing happened can be hard to track down – Marc Gravell Jan 27 '20 at 10:25
  • Not a C# programmer, but the fact that the definition of `_` is after the return instruction bugs me, and I can't find a good reference to understand what feature I don't know. Any quick link I can use to understand more? Thanks. – bracco23 Jan 27 '20 at 16:19
  • 1
    @bracco23 "local functions"; nothing says they can't be declared after `return` – Marc Gravell Jan 27 '20 at 16:34
  • @MarcGravell touchè, I was so focused on the definition itself I lost sight of it being of a functiona and not of a variable. – bracco23 Jan 27 '20 at 16:35
  • 7
    Minor nit: the characteristic of local functions that make them local is that their *name* is only in scope in the local neighbourhood of the declaration. A local function can be *called* from anywhere, by, say, passing out a delegate to it. Locality is about controlling access to *names*, not to *the thing named*. – Eric Lippert Jan 27 '20 at 18:52
  • @EricLippert good nit, +1 – Marc Gravell Jan 27 '20 at 19:21
1

IEnumerable<TResult> _() {} is local function that called in return _();

Kovpaev Alexey
  • 1,725
  • 6
  • 19
  • 38