C# Behind the scenes – Local Functions

The second “Behind the scenes” article, will be about local function.

This is much simple from previous post about yield keyword.
In short, local function translated to a method of the class.

Example 1

void M(int o)
{
    int Multiply(int n) => n * 2;

    foreach (var i in new List<int> { 1, 2, 3, 4, 5 })
    {
        Console.WriteLine(Multiply(i));
    }
}


Multiply will translate to static method in M class:

static int Multiply(int n)
{
    return n*2;
}

OK this is very simple, but what if M class has already method with the same signature (Multiply(int n))?

The answer is that the compiler will generate name that not confuse with existing class method.
In this case, the name will be the parent method name and then the method name _Multiply (This is not what will be in reality and there is no commitment to what will be in reality, it is only for the purpose of explanation of how in generally the compiler handle this case.)

Example 2

void M(int o)
{
    int Multiply(int n) => n * 2;

    foreach (var i in new List<int> { 1, 2, 3, 4, 5 })
    {
        Console.WriteLine(Multiply(i));
    }
}
void M(bool o)
{
    int Multiply(int n) => n * 2;

    foreach (var i in new List<int> { 1, 2, 3, 4, 5 })
    {
        Console.WriteLine(Multiply(i));
    }
}

Note, there is a two local functions that their method parents called M.
For this case, the compiler will add index for the name and the methods names will be _Multiply1, _Multiply2 etc.

Example 3

void M(int o)
{
    int Multiply(int n) => obj == null ? 0 : n * 2;

    foreach (var i in new List<int> { 1, 2, 3, 4, 5 })
    {
        Console.WriteLine(Multiply(i));
    }
}

Note, obj is a class member, so Multiply can’t be static.
Indeed in this case the generated method will be an instance method with access to this.

Example 4

void M(int o)
{
    int Multiply(int n) => o * n;

    foreach (var i in new List<int> { 1, 2, 3, 4, 5 })
    {
        Console.WriteLine(Multiply(i));
    }
}

Do you see the problem? we use the o parameter inside the local function, how this can be done? Remember that Multiply is a different method (static or instance) in the class, so how is know about parameter passed to M?

The solution for this (and not just for this, we will see in later posts that C# compiler use it in more cases) is to generate a new nested type named for example ‘ParentClass_DisplayClass_0’ (see below) and this object has member to hold the parameter o.

private struct <>c__DisplayClass0_0
{
    public int o;
}

Now in M method, the struct is created and the parameter is saved and when the local function code is run, this struct is sent as by ref parameter and this how the local function can use it.

Example 5

void M(int o)
{
    int Multiply(int n) => obj == null ? 0 : o * n;

    foreach (var i in new List<int> { 1, 2, 3, 4, 5 })
    {
        Console.WriteLine(Multiply(i));
    }
}

Now we use parameter and instance member.
For this ‘ParentClass_DisplayClass_0’ also generated and it holds two fields, one for parameter and the second for this. The local function will generated as static, and not as we saw in example 3, even that it use an instance member, because the generated type is hold for us the this. The rest is same as example 4.

Homework: What do you think will be the behavior if the M method is within a struct and not within a class and inside the local function we want to use obj instance member?

See more C# behind the scenes articles

Advertisements
This entry was posted in .NET, c# and tagged , , , . Bookmark the permalink.

One Response to C# Behind the scenes – Local Functions

  1. Pingback: C# Behind the scenes | My Coding Place

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s