ARPL 1.0.5-rc
See the version list below for details.
dotnet add package ARPL --version 1.0.5-rc
NuGet\Install-Package ARPL -Version 1.0.5-rc
<PackageReference Include="ARPL" Version="1.0.5-rc" />
<PackageVersion Include="ARPL" Version="1.0.5-rc" />
<PackageReference Include="ARPL" />
paket add ARPL --version 1.0.5-rc
#r "nuget: ARPL, 1.0.5-rc"
#:package ARPL@1.0.5-rc
#addin nuget:?package=ARPL&version=1.0.5-rc&prerelease
#tool nuget:?package=ARPL&version=1.0.5-rc&prerelease
ARPL (Advanced Result Pattern Library)
A lightweight C# library providing robust discriminated unions for error handling and functional programming patterns. ARPL offers two main types: Either<L,R>
for generic discriminated unions and SResult<R>
for specialized success/error handling.
Features 🚀
- Either<L,R> - A generic discriminated union that can hold one of two possible types
- SResult<R> - A specialized result type for handling success/error scenarios
- Implicit conversions between
Either<Error,R>
andSResult<R>
- Pattern matching support for elegant value handling
- Type-safe error handling without exceptions
- Functional programming friendly design
Type Features
Either<L,R>
Left(L value)
- Creates a new Either instance containing a left valueRight(R value)
- Creates a new Either instance containing a right valueIsLeft
- Indicates if the instance contains a left valueIsRight
- Indicates if the instance contains a right valueMatch
- Pattern matching for transforming or handling the contained valueMatchAsync
- Asynchronous pattern matching for handling the contained valueMap
- Transforms the right value using a mapping function (if present)MapAsync
- Transforms the right value using an async mapping function (if present)Apply
- Transforms both left and right values into a new EitherApplyAsync
- Asynchronously transforms both left and right values into a new Either
SResult<R>
Success(R value)
- Creates a new success resultError(Error value)
- Creates a new error resultIsSuccess
- Indicates if the result represents successIsFail
- Indicates if the result represents an errorSuccessValue
- Gets the success valueErrorValue
- Gets the error valueMatch
- Pattern matching for transforming or handling the resultMatchAsync
- Asynchronous pattern matching for handling the resultMap
- Transforms the success value using a mapping function (if present)MapAsync
- Transforms the success value using an async mapping function (if present)Apply
- Transforms both error and success values into a new SResultApplyAsync
- Asynchronously transforms both error and success values into a new SResult
Getting Started 🏃
Installation
Install via NuGet:
Install-Package ARPL
Basic Usage
Using Either<L,R>
using Arpl.Core;
// Create Either instances
Either<string, int> leftValue = Either<string, int>.Left("error message");
Either<string, int> rightValue = Either<string, int>.Right(42);
// Pattern match to handle both cases
leftValue.Match(
left => Console.WriteLine($"Left value: {left}"),
right => Console.WriteLine($"Right value: {right}"));
// Asynchronous pattern matching
await rightValue.MatchAsync(
async left => { await Task.Delay(10); Console.WriteLine($"Left async: {left}"); return 0; },
async right => { await Task.Delay(10); Console.WriteLine($"Right async: {right}"); return right; }
);
// Mapping right value
Either<string, string> mapped = rightValue.Map(val => $"Number: {val}");
// Async mapping
Either<string, string> asyncMapped = await rightValue.MapAsync(async val => {
await Task.Delay(10);
return $"Number: {val}";
});
// Chain operations with Apply
var result = either
.Apply(
left => Either<Error, int>.Left(left), // Propagate error
right => ValidateNumber(right) // Returns Either<Error, int>
)
.Apply(
left => Either<Error, string>.Left(left), // Propagate error
right => FormatNumber(right) // Returns Either<Error, string>
);
// Async operations with ApplyAsync
await either.ApplyAsync(
async left => {
await Task.Delay(10);
return Either<Error, string>.Left(left);
},
async right => {
await Task.Delay(10);
return Either<Error, string>.Right($"Processed: {right}");
}
);
Using SResult<R>
// Create success result
SResult<int> success = SResult<int>.Success(42);
// Create error result
SResult<int> error = SResult<int>.Error(new Error("Something went wrong"));
// Pattern match
var message = success.Match(
fail => $"Error: {fail.Message}",
value => $"Success: {value}"
);
// Asynchronous pattern matching
await error.MatchAsync(
async fail => { await Task.Delay(10); return $"Async error: {fail.Message}"; },
async value => { await Task.Delay(10); return $"Async success: {value}"; }
);
// Mapping success value
SResult<string> mapped = success.Map(val => $"Result: {val}");
// Async mapping
SResult<string> asyncMapped = await success.MapAsync(async val => {
await Task.Delay(10);
return $"Result: {val}";
});
// Chain operations with Apply
var result = sresult
.Apply(
error => SResult<int>.Error(error), // Propagate error
success => ValidateNumber(success) // Returns SResult<int>
)
.Apply(
error => SResult<string>.Error(error), // Propagate error
success => FormatNumber(success) // Returns SResult<string>
);
// Async operations with ApplyAsync
await sresult.ApplyAsync(
async error => {
await Task.Delay(10);
return SResult<string>.Error(error);
},
async success => {
await Task.Delay(10);
return SResult<string>.Success($"Processed: {success}");
}
);
// Check result type
if (success.IsSuccess)
Console.WriteLine($"Success value: {success.SuccessValue}");
if (error.IsFail)
Console.WriteLine($"Error value: {error.ErrorValue}");
Error Handling
ARPL provides a flexible error handling system that allows you to work with both single errors and collections of errors. The Error
class serves as the base for all error types, and the ErrorCollection
allows you to aggregate multiple errors together.
Single Errors
// Create a simple error
var error = Errors.New("Invalid input", "ERR001");
// Create an unexpected error from an exception
var unexpectedError = Errors.New(new Exception("Database connection failed"));
Multiple Errors
When you need to collect and combine multiple errors, use ErrorCollection
:
// Start with an empty error collection
var errors = Errors.EmptyError();
// Add errors as they are found
errors.Add(Errors.New("Invalid email", "VAL001"));
errors.Add(Errors.New("Password too short", "VAL002"));
// You can also combine errors using the + operator
var error1 = Errors.New("Field required", "VAL003");
var error2 = Errors.New("Invalid format", "VAL004");
var combined = error1 + error2; // Creates a new ErrorCollection
// Use in result types
return SResult<User>.Error(errors); // Works with both single Error and ErrorCollection
Bespoke Errors
ARPL allows you to create custom error types by extending the Error
class. This enables you to create domain-specific errors that carry meaningful context for your application:
public record NotFoundError : Error
{
public NotFoundError(string entityType, string identifier)
{
EntityType = entityType;
Identifier = identifier;
}
public string EntityType { get; }
public string Identifier { get; }
public override string Message => $"{EntityType} with id {Identifier} was not found";
public override bool IsExpected => true;
}
// Usage example:
public async Task<SResult<User>> GetUserById(string userId)
{
var user = await _repository.FindUserById(userId);
if (user == null)
return SResult<User>.Error(new NotFoundError("User", userId));
return SResult<User>.Success(user);
}
// Pattern matching with custom error
var result = await GetUserById("123");
var message = result.Match(
fail => fail is NotFoundError nf
? $"Could not find {nf.EntityType} {nf.Identifier}"
: "Unknown error",
success => $"Found user: {success.Name}"
);
Bespoke errors provide several benefits:
- Type-safe error handling with pattern matching
- Rich error context specific to your domain
- Clear distinction between expected and unexpected errors
- Consistent error handling across your application
Implicit Conversions
ARPL supports implicit conversions between Either<Error,R>
and SResult<R>
, making it seamless to work with both types:
// Convert from Either to SResult
Either<Error, int> either = Either<Error, int>.Right(42);
SResult<int> result = either; // Implicit conversion
// Convert from SResult to Either
SResult<int> sresult = SResult<int>.Success(42);
Either<Error, int> converted = sresult; // Implicit conversion
Note: The implicit conversion only works for
Either<Error, R>
andSResult<R>
. Attempting to convert other types will throw an exception.
Best Practices
- Use
Either<L,R>
when you need a generic discriminated union - Use
SResult<R>
for specific success/error handling scenarios - Leverage pattern matching with
Match
for clean and safe value handling - Prefer using the type system for error handling instead of exceptions
StaticFactory Helpers
For a more functional and concise style, ARPL provides the StaticFactory
class, which offers utility methods to create instances of SResult
and Either
in a direct and expressive way:
using static Arpl.Core.StaticFactory;
// Create a success result
var success = Success(42); // SResult<int>
// Create a failure result
var fail = Fail<int>(new Error("fail")); // SResult<int>
// Create an Either with a left value
var left = Left<string, int>("error"); // Either<string, int>
// Create an Either with a right value
var right = Right<string, int>(42); // Either<string, int>
Available Methods
Success<T>(T value)
: Creates a successfulSResult<T>
.Fail<T>(Error value)
: Creates a failedSResult<T>
.Left<L, R>(L value)
: Creates anEither<L, R>
with a left value.Right<L, R>(R value)
: Creates anEither<L, R>
with a right value.
These methods make it easier to create values for functional flows and tests, making your code cleaner and more readable.
Contributing 🤝
Contributions are welcome! Feel free to submit issues and pull requests.
License 📄
This project is licensed under the MIT License - see the LICENSE file for details.
Disclaimer: This README was generated and reviewed with the assistance of Windsurf AI.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net6.0
- No dependencies.
-
net7.0
- No dependencies.
-
net8.0
- No dependencies.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on ARPL:
Package | Downloads |
---|---|
ARPL.AspNetCore
A lightweight C# library providing robust discriminated unions for error handling and functional programming patterns. ARPL offers two main types: Either<L,R> for generic discriminated unions and SResult<R> for specialized success/error handling. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last Updated |
---|---|---|
1.0.12 | 32 | 9/28/2025 |
1.0.11 | 115 | 9/13/2025 |
1.0.10 | 152 | 5/2/2025 |
1.0.9 | 162 | 5/1/2025 |
1.0.8 | 184 | 4/30/2025 |
1.0.7 | 166 | 4/30/2025 |
1.0.6 | 171 | 4/29/2025 |
1.0.5 | 106 | 4/26/2025 |
1.0.5-rc | 165 | 4/25/2025 |
1.0.4 | 169 | 4/25/2025 |
1.0.3 | 177 | 4/24/2025 |
1.0.2 | 121 | 4/19/2025 |
1.0.1 | 215 | 4/16/2025 |
1.0.0 | 228 | 4/15/2025 |