Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

compiler optimisation when returning strings

If I have

private string Foo(string decrypted)
{
    return decrypted.Substring(blah);
}

and

private string Foo(string decrypted)
{
    string s = decrypted.Substring(blah);
    return s;
}

Is this the same? Is the compiler able to remove s?

How about

private string Foo(string decrypted)
{
    string s = decrypted.Substring(blah);
    string t = s;
    return t;
}

?

Thanks.

like image 874
Sam Leach Avatar asked Jun 11 '13 13:06

Sam Leach


2 Answers

I was curious, so I tried it out (using LINQPad 4 with optimizations). This is what I got:

private string Foo(string decrypted)
{
    return decrypted.Substring(0);
}
Foo:
IL_0000:  ldarg.1     
IL_0001:  ldc.i4.0    
IL_0002:  callvirt    System.String.Substring
IL_0007:  ret        

private string Foo(string decrypted)
{
    string s = decrypted.Substring(0);
    return s;
}
Foo:
IL_0000:  ldarg.1     
IL_0001:  ldc.i4.0    
IL_0002:  callvirt    System.String.Substring
IL_0007:  stloc.0     // s
IL_0008:  ldloc.0     // s
IL_0009:  ret     

private string Foo(string decrypted)
{
    string s = decrypted.Substring(0);
    string t = s;
    return t;
}
Foo:
IL_0000:  ldarg.1     
IL_0001:  ldc.i4.0    
IL_0002:  callvirt    System.String.Substring
IL_0007:  stloc.0     // s
IL_0008:  ldloc.0     // s
IL_0009:  stloc.1     // t
IL_000A:  ldloc.1     // t
IL_000B:  ret    

It appears the compiler doesn't optimize away s or t, however, I suspect the JIT interpreter would.

like image 198
p.s.w.g Avatar answered Sep 23 '22 05:09

p.s.w.g


It looks to me like the question is basically "does the C# compiler support named return value optimization (NRVO)?"

That's a reasonable question, I suppose, but like delnan points out, it's not particularly relevant because of the fact that strings in C# are reference types. If you're a C++ programmer, you can think of reference types as essentially equivalent to pointers. So although you are returning the string by value, you're really only returning the reference by value, not the object itself. It's just as if you were returning the pointer address by value. A copy of the entire string object need not be made, so the optimization gains you very little. The only reason you need NRVO is to avoid suffering the performance hit of a large and expensive copy, but copying a pointer/reference is not expensive.

However, if you had given a different example that used a value type rather than a reference type (e.g., a large structure), then there might be a significant performance improvement to be gained by implementing NRVO. Unfortunately, even in this case, I do not believe that the C# compiler does this. I suppose the JITer might; I can't say for sure. (And if it isn't done now, it could always be added in future versions. Although such large structures are found only rarely in C# code, so it's unlikely this is at the top of the performance team's list of goals.)

For more details, Jon Skeet's article on References and Values in C# is recommended reading.

like image 37
Cody Gray Avatar answered Sep 21 '22 05:09

Cody Gray