New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal: Save space by removing delegates from TryPick and Map autogenerated implementations #72
Comments
This is really good stuff, a big win! Will welcome PR with open arms.
It would be an interesting exercise to see what the addembly sizes are if
c# 9 static lambdas were used with the original code. Would they be
optimized away, or still take up lots of space...
…On Mon, 28 Dec 2020, 2:06 pm Zev Spitz, ***@***.***> wrote:
The autogenerated code for the TryPickX method currently looks like this:
public OneOf<T0, T1, TResult, T3> MapT2<TResult>(Func<T2, TResult> mapFunc)
{
if(mapFunc == null)
{
throw new ArgumentNullException(nameof(mapFunc));
}
return Match<OneOf<T0, T1, TResult, T3>>(
input0 => input0,
input1 => input1,
input2 => mapFunc(input2),
input3 => input3
);
}
Each delegate requires the compiler to generate its own class. Similarly,
for Map:
public OneOf<T0, T1, TResult, T3> MapT2<TResult>(Func<T2, TResult> mapFunc)
{
if(mapFunc == null)
{
throw new ArgumentNullException(nameof(mapFunc));
}
return Match<OneOf<T0, T1, TResult, T3>>(
input0 => input0,
input1 => input1,
input2 => mapFunc(input2),
input3 => input3
);
}
Using autogenerated implementations that don't have delegates, e.g. for
TryPick:
public bool TryPickT1(out T1 value, out OneOf<T0, T2, T3, T4> remainder)
{
value = IsT1 ? AsT1 : default;
switch (_index)
{
case 0: remainder = OneOf<T0, T2, T3, T4>.FromT0(AsT0); break;
case 1: remainder = default; break;
case 2: remainder = OneOf<T0, T2, T3, T4>.FromT1(AsT2); break;
case 3: remainder = OneOf<T0, T2, T3, T4>.FromT2(AsT3); break;
case 4: remainder = OneOf<T0, T2, T3, T4>.FromT3(AsT4); break;
default: throw new InvalidOperationException();
}
return IsT1;
}
and for Map
public OneOf<T0, TResult, T2, T3, T4> MapT1<TResult>(Func<T1, TResult> mapFunc)
{
if(mapFunc == null)
{
throw new ArgumentNullException(nameof(mapFunc));
}
switch (_index)
{
case 0: return OneOf<T0, TResult, T2, T3, T4>.FromT0(AsT0);
case 1: return OneOf<T0, TResult, T2, T3, T4>.FromT1(mapFunc(AsT1));
case 2: return OneOf<T0, TResult, T2, T3, T4>.FromT2(AsT2);
case 3: return OneOf<T0, TResult, T2, T3, T4>.FromT3(AsT3);
case 4: return OneOf<T0, TResult, T2, T3, T4>.FromT4(AsT4);
default: throw new InvalidOperationException();
}
}
reduces the file size, as follows:
File Current Reduced
OneOf.dll 233K 106K
OneOf.Extended.dll 9.9M 1.9M
I've never had much need to consider this before, but I'm wondering if
there are other ways to reduce the size of the IL? Maybe use later language
features such as switch expressions? Or perhaps replace internal calls to
FromX with a generic FromIndex method with a generic parameter?
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#72>, or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AACDJ6T2CL7UP35HLCNAR4LSXCGF3ANCNFSM4VMCFV7A>
.
|
Would you consider using a higher C# language version? Most of the new syntax is supported even on earlier framework versions (https://medium.com/@SergioPedri/enabling-and-using-c-9-features-on-older-and-unsupported-runtimes-ce384d8debb). Switch expressions in particular could be very useful. If nothing else, it would make the auto-generated code easier to maintain, by outputting less. |
Using Another observation: Release is slightly smaller than Debug:
@mcintyre321 Can I set the language version to C# 9? Even though there are some parts of C# 9 that aren't supported on older framework versions? As I noted above, it'll make the autogenerated code easier to maintain. |
The autogenerated code for the
TryPickX
method currently looks like this:Each delegate requires the compiler to generate its own class. Similarly, for
Map
:Using autogenerated implementations that don't have delegates, e.g. for
TryPick
:and for
Map
reduces the file size, as follows:
I've never had much need to consider this before, but I'm wondering if there are other ways to reduce the size of the IL? Maybe use later language features such as switch expressions? Or perhaps replace internal calls to
FromX
with a genericFromIndex
method with a generic parameter?How much of a reduction would be needed to move OneOf.Extended back into the original dll?
The text was updated successfully, but these errors were encountered: