Add expected-error ProcessResult variant - #10
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a new
ProcessResult<T, TError>variant for operations that can fail in expected, explicitly modeled ways, while keeping the existingProcessResult<T>focused on value-or-exception scenarios.This change is intentionally small and follows the same distinction made by dotNext's result types: expected application/domain outcomes and exceptional failures are different concepts and should not be forced through the same error channel.
When to use each result type
ProcessResult<T>Use
ProcessResult<T>when an operation intentionally captures an exception as part of its result contract.Typical examples include boundary code that needs to inspect, forward, log, or defer an exception rather than immediately allowing it to propagate.
Expected application or domain outcomes should not be converted into exceptions merely to fit this type. Unexpected or exceptional failures should normally continue to propagate as exceptions unless a concrete boundary has a reason to capture them.
ProcessResult<T, TError>Use
ProcessResult<T, TError>when failure is an anticipated part of normal application or domain flow and callers are expected to branch on a known error state.Examples include:
TErroris constrained to an enum. Its default value is reserved to represent success, so error enums should use non-default values for actual failures. A neutral member such asNone = 0may be defined when that improves readability.This type is intentionally not an exception container. Exceptional failures should still throw unless the calling boundary deliberately chooses exception-capturing semantics via
ProcessResult<T>.API
ProcessResult<T, TError>provides:Success(...)andFailure(...)factories,Value,ValueOrDefault,Error,IsSuccessful,TryGet(...),TErrorvalue from being used as a failure,Attempting to read
Valuefrom an unsuccessful expected-error result throwsInvalidOperationException, because the caller is attempting to consume a value that the result does not contain.Existing
ProcessResult<T>documentationThe XML documentation for the existing exception-based result type has been expanded to make the distinction between expected failures and captured exceptions explicit. No existing
ProcessResult<T>behavior is changed.Motivation
The immediate use case came from Helm's Goal/Objective application services. Operations such as moving a Goal can legitimately fail because the Goal or destination LifeDomain no longer exists. Those are expected application outcomes, not exceptional runtime failures.
Rather than returning an ambiguous
false, inventing a Helm-specific result abstraction, or wrapping ordinary not-found states in exceptions, AppToolkit can provide a reusable expected-error result type alongside its existing exception result type.This keeps the two responsibilities distinct:
The goal is not to reproduce dotNext's broader monadic API. This adds only the result semantics currently justified by real application use, with future additions driven by actual consumers.