-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
API Proposal: UnreachableException #35324
Comments
How would this interact with the proposed "never" return type (dotnet/csharplang#538)? Is this API a point-in-time patch until that feature comes online? Presumably code coverage analyzers could already look for methods marked with It would be helpful to clarify this exception's place in the ecosystem in a world where both of these capabilities exist. |
Consider a random example taken from Roslyn: In this case, the method does sometimes return (in fact, if the unreachability assumption is correct, it always returns), so neither Applying Also, code coverage should expect not to cover the It would actually also be the reverse -- any code on a code path that inevitably leads to |
This seems very useful to me. Sometimes, a code location is to be considered unreachable. Having this exception type confers the following benefits:
Adding this type would not be a complicated change. It can easily be trimmed. The assembly size increase would be modest. I have defined this type myself and I'm using it. |
@GrabYourPitchforks Any other concerns or can this be put into the review queue? |
Marking this as ready for review. Open question for reviewers: given that the target scenario is for debugging, code coverage, and other dev tools; would System.Diagnostics be a more appropriate namespace than System? |
I like this and it'd be also useful for tools like IL linker which have to now uses |
System.Diagnostics feels more appropriate to me. In all the cases I'd see myself using it I currently have a Debug.Fail, then the exception so the compiler doesn't tell me my execution flow makes no sense. If we end up doing a public ThrowHelper-type API for ArgumentNullException (#48573) then we'd probably want one here, too. |
The only case where I'd use this is when I have an unexpected case in a switch statement of something, what I usually do is just throw a regular But, for new code, I'd certainly consider using this exception type, as @marek-safar already mentioned, This would be good for some applications which now had to use |
@FilipToth Per earlier discussion, the best use cases seem to be debuggers, flow analyzers, and other design-time and diagnostics tools. I don't think anybody would go back and change their existing code to use this API unless they want the benefits these tools offer. |
#nullable enable
using System.Runtime.Serialization;
namespace System
{
public sealed class UnreachableException : SystemException
{
public UnreachableException()
: base("The program executed an instruction that was thought to be unreachable.")
{
}
public UnreachableException(string? message)
: base(message)
{
}
public UnreachableException(string? message, Exception? innerException)
: base(message, innerException)
{
}
}
} |
For reference: |
@bartonjs Shouldn't this be under System.Diagnostics as previously discussed? |
Stack overflow is hard fail fast. We do not allow any handling of it in managed code. (.NET Framework allowed handling stackoverflow exceptions using SQL hosting interfaces. We do not have those in .NET Core.)
Thread abort was not a simple uncatchable exception. The thread abort switched the thread into a special aborting mode, it was about much more than just rethrowing exception at the end of catch block. We do not have concept of uncatchable exceptions in the runtime and I do not think we should be introducing it for this one. The only difference between uncatchable exceptions and |
Personally I think this should not have any kind of uncatchable behavior. Consider a plugin system, like Roslyn analyzers: an Also, there's already a somewhat similar type, |
What would happen if a single request in a web app encounters such an exception? Would thread or process be torn down? That's unacceptable. The application must keep running and keep serving traffic. Bugs happen all the time. Even state corrupting ones. We can't tear down the process when that happens. Web apps also rarely experience true state corruption because, usually, requests are isolated and the request state is cleanly thrown away at the end of request processing. |
For the same reason, it is not possible to use This is why I suggested an AssertFailedException. The design concept is very much like this It's simply an exception that anyone can use to their liking. There is no runtime integration. Nothing in the framework reacts specially to that. But we can standardize the community on using these two exception types to expect common semantics. I consider that to be valuable. |
One suggestion was |
Why does this need a constructor for Inner Exceptions? Is there any use case to nest Exceptions in UnreachableExceptions? |
All exceptions have these constructors; it's the standard pattern. |
Could this type be used for those like me who want to use it at runtime as well (to notify any application that something unexpected happened inside of one of it's dependencies)? Currently I have mine stuck between these:
Although most of my libraries target ns2.0 I do use reflection to probe for the existence of newer features in the runtime and then if they are not found fallback to the ones defined in ns2.0. I could do a throw helper in my ns2.0 libraries with things like:
|
@AraHaan There's nothing terribly unique about this exception type from a runtime perspective. You should be able to use reflection to instantiate it just as you would any other type, cast to the base |
Feel free to assign me 😄 |
The PR observed that there were still some floating points. Marking as review-ready and blocking so we discuss them today to unblock the PR. |
Great 👍🏼! Is this a small change (i.e. just implement the API + tests) or are there other changes that need to be made? |
We seem to have hit the most agreeable (perhaps "least disagreeable") position with System.Diagnostics, on the basis that it's rather like an assert ( namespace System.Diagnostics
{
public sealed class UnreachableException : Exception
{
public UnreachableException()
: base("The program executed an instruction that was thought to be unreachable.")
{
}
public UnreachableException(string? message)
: base(message)
{
}
public UnreachableException(string? message, Exception? innerException)
: base(message, innerException)
{
}
}
} |
Since this is only a small change, I'm happy to work on that issue. |
There's already an in-flight PR for it. |
I know this is a bit late, but I was surprised the discussion didn't float the idea that this exception is quite similar (at least in my mind) in concept to |
Motivation
This exception is expected to never be thrown. Code coverage tools might choose to ignore non-coverage of the statement or branch that throws this exception. In fact, coverage of such a statement or branch is undesirable, as it would indicate that the code is making an invalid assumption.
Proposal
See Also
The text was updated successfully, but these errors were encountered: