Skip to content
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

Improve handling of unit results #6

Open
thinker227 opened this issue Jan 16, 2024 · 0 comments
Open

Improve handling of unit results #6

thinker227 opened this issue Jan 16, 2024 · 0 comments
Labels
enhancement New feature or request

Comments

@thinker227
Copy link
Owner

thinker227 commented Jan 16, 2024

There are situations in which one might want a non-generic Result which only contains an error, eg. methods which would usually return void but might also return errors. Currently the best alternative to this would be defining a global Result alias for Result<SomeUnitType>.

The unit problem

The problem is where this SomeUnitType should come from. The library should purposefully not include a unit type of its own as to not contribute to "unit type pollution" among the .NET ecosystem. System.ValueTuple is a strong potential contender for a built-in unit type as it is an uninteresting struct type with no associated data. It would absolutely be preferable to automatically include this into the library by default, though without forcing the usage of specifically System.ValueTuple.

A source-generated solution

A possible solution which would provide a nearly built-in development experience while also providing the freedom of not being constrained to a particular unit type would be to use a source generator and accompanying analyzer(s). The source generator's API surface would be a single assembly-level attribute:

[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
public sealed class UnitResultAttribute<T> : Attribute;

// usage:
[assembly: UnitResult<SomeUnitType>]

An incremental source generator would react to the usage of UnitResult and generate a global using statement for Result<SomeUnitType> along with several utility methods. Example:

// generated

global using Result = Rascal.Result<SomeUnitType>;
global using static UnitResultPrelude;

internal static class UnitResultPrelude
{
    public static Result<SomeUnitType> Empty() => new(new SomeUnitType());

    public static Result<SomeUnitType> EmptyErr(Error error) => new(error);
}

If the user does not wish to include the global using static UnitResultPrelude;, the attribute could contain an optional flag to disable generation of it.

The benefit of this solution is that the API surface is minimal but could provide an arbitrary amount of complexity. The obvious downside is the complexity of a source generator, although since an analysis project with existing analyzers already exists, it wouldn't be very difficult to add a source generator. The generator itself would also be very efficient as it would be incremental and only have to react to a single attribute on the assembly-level, with some additional validity checks.

@thinker227 thinker227 added the enhancement New feature or request label Jan 16, 2024
@thinker227 thinker227 changed the title Improvde handling of unit results Improve handling of unit results Feb 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant