Description
This simple code snippet:
let f() = string 4
produces this IL code that involves a redundant boxing and type checking:
public static string f()
{
object obj = 4;
if (obj != null)
{
IFormattable formattable = obj as IFormattable;
if (formattable != null)
{
IFormattable formattable2 = formattable;
return formattable2.ToString(null, CultureInfo.InvariantCulture);
}
object obj2 = obj;
return obj2.ToString();
}
return "";
}
The compiler knows that 4
is an integer and implements IFormattable
. For value types and sealed classes known to implement it, emitting a direct call to ToString
with the invariant culture passed (and the constrained.
IL prefix) would be much better. Same with the eligible types that are known to not implement it.
For all other cases (non-sealed reference types that do not implement IFormattable
), the existing behavior is acceptable (no boxings) and backwards-compatible. Performance-concerned developers can always directly call ToString()
.
There might be a problem with types that might stop implementing IFormattable
at a later version of the library, but this is a breaking change that should require recompilation and we should not be concerned with such scenarios.