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

Consider using enum error code instead of nested exception types #71

Closed
AArnott opened this issue Feb 13, 2024 · 4 comments
Closed

Consider using enum error code instead of nested exception types #71

AArnott opened this issue Feb 13, 2024 · 4 comments

Comments

@AArnott
Copy link
Contributor

AArnott commented Feb 13, 2024

An enum error type in UDL produces a C# exception with a nested derived exception type for each enum value.
For example:

internal class LightWalletException: UniffiException {
    LightWalletException(string message): base(message) {}

    // Each variant is a nested class
    // Flat enums carries a string error message, so no special implementation is necessary.
    
    public class InvalidUri: LightWalletException {
        public InvalidUri(string message): base(message) {}
    }
    
    public class InvalidHandle: LightWalletException {
        public InvalidHandle(string message): base(message) {}
    }
    
    public class Other: LightWalletException {
        public Other(string message): base(message) {}
    } 
}

But these exception types don't hold any unique properties. Why not nest this inside the exception instead?

	public enum ErrorCode
	{
		Other,
		InvalidUri,
		InvalidHandle,
	}
	public required ErrorCode Code { get; init; }

It results in less metadata. And in .NET in general, very finely grained exception types are discouraged. The enum approach still allows exception filters to catch specific cases. For example:

try {
    callIntoInterop();
} catch (LightWalletException ex) when (ex.Code == LightWalletException.ErrorCode.InvalidUri) {
  // handle invalid uri
}

This is all assuming that UDL doesn't support carrying distinct error enums data across the interop boundary. If different error enum values can actually carry distinct fields in UDL (as they can in rust) then C# should probably retain a distinct exception type for each one.

@AArnott
Copy link
Contributor Author

AArnott commented Feb 13, 2024

In exploring the possibility of unique sets of fields for each error enum member, I discovered that UDL can express such enums:

[Enum]
interface LightWalletError {
	InvalidUri();
	InvalidHandle();
	Other(string message);
};

But uniffi-bindgen-cs generates uncompilable C# code when I reference this type in a [Throws=LightWalletError] attribute.

@AArnott
Copy link
Contributor Author

AArnott commented Feb 13, 2024

This worked:

[Error]
interface LightWalletError {
	InvalidArgument(string message);
	InvalidUri();
	SqliteClientError(string message);
	Other(string message);
};

So I like that you have nested exception types now, since they capture the fields on the enumerated error.

@AArnott AArnott closed this as not planned Won't fix, can't repro, duplicate, stale Feb 13, 2024
@arg0d
Copy link
Collaborator

arg0d commented Feb 14, 2024

We could think about generating ErrorCode instead of exception hierarchies when error do not contain associated fields. That is how enums are implemented. Regular enums are implemented as enum, associated enums are implemented as class hierarchies.

But if you don't see this as a problem anymore, maybe there is no reason to change how errors are implemented.

@AArnott
Copy link
Contributor Author

AArnott commented Feb 14, 2024

Well, it may be a good idea still, but there's value enough in the exception details that I've now discovered how to unlock that I don't think it'll be a wish item for me.

It's #41 that I really want. And I'm an expert in async... if only I had time to research the uniffi protocol itself, I'd send you a PR to add async support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants