Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 29 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

**Explicit, composable control flow for C#**

## Changelogs
[1.0.1 to 1.0.2](https://github.com/bargross/zero-null/blob/main/Changelog-1.0.1-to-1.0.2.md)

## What is this library?

ZeroNull brings **functional control-flow patterns** to C#. It provides lightweight, immutable structs like `Option<T>`, `Result<T, TError>`, and `Either<TLeft, TRight>` that let you model absence, errors, and branching logic explicitly in your type signatures—without exceptions, nulls, or hidden side-effects.
Expand All @@ -28,27 +31,17 @@ ZeroNull brings **functional control-flow patterns** to C#. It provides lightwei
| Type | Purpose | Key methods |
| :--- | :--- | :--- |
| `Option<T>` | A value that may be present (`Some`) or absent (`None`). | `Map`, `Bind`, `Match`, `ValueOr`, LINQ support (`Select`, `SelectMany`) |
| `Result<T, TError>` | A value that is either successful (`Ok`) or carries an error (`Error`). | `Map`, `Bind`, `MapError`, `Match`, LINQ support (`Select`, `SelectMany`) |
| `Either<TLeft, TRight>` | A value that can be one of two possible types. By convention, `Left` represents failure/alternative, `Right` represents success. | `IsLeft`, `IsRight`, `Left`, `Right`, `Match`<br/><br/>**Extension methods:**<br/>• `Select` / `SelectMany` – LINQ query syntax support (works on the `Right` side)<br/>• `Where` – filter `Right` (with custom `Left` on false) or filter `Left`<br/>• `MapLeft` / `MapRight` – transform one side while keeping the other<br/>• `BindLeft` / `BindRight` – bind over one side to produce a new `Either` |

### Either‑specific extension method details
| `Result<T, TError>` | A value that is either successful (`Ok`) or carries an error (`Error`). | `Map`, `Bind`, `MapError`, `Match`, LINQ support |
| `Validation<TError, TValue>` | Accumulates multiple errors; can be `Valid` (with a value) or `Invalid` (with multiple errors). | `Map`, `Bind`, `Apply`, `Combine`, `Match`, LINQ support |
| `Either<TLeft, TRight>` | A value that can be one of two possible types (left or right). Typically used for two alternative success cases or a general union. | `MapLeft`, `MapRight`, `BindLeft`, `BindRight`, `Match`, `IsLeft`, `IsRight` |

| Method | Description |
| :--- | :--- |
| `Select(selector)` | Projects the `Right` value when the `Either` is in the `Right` state. Enables LINQ query syntax. |
| `SelectMany(binder, projector)` | Chains two `Either` operations that work on `Right` values. Short‑circuits on the first `Left`. |
| `Where(predicate, leftOnFalse)` | Filters the `Right` value; if the predicate fails, becomes `Left(leftOnFalse)`. |
| `Where(leftPredicate, leftOnFalse)` | Filters the `Left` value; if the predicate fails, becomes `Left(leftOnFalse)`. |
| `MapLeft(mapper)` | Applies `mapper` to the `Left` value if present; otherwise preserves the `Right`. |
| `MapRight(mapper)` | Applies `mapper` to the `Right` value if present; otherwise preserves the `Left`. |
| `BindLeft(binder)` | If `Left`, applies `binder` to produce a new `Either` (can change `Left` type, or even become `Right`). |
| `BindRight(binder)` | If `Right`, applies `binder` to produce a new `Either` (can change `Right` type, or even become `Left`). |

**Core features:**
- Immutable, `readonly struct` – zero heap allocation in hot paths.
- LINQ query comprehension (`from...select...`).
- Exhaustive pattern matching with `Match`.
- Async extensions (optional – available in a separate package).
- **Immutable, `readonly struct`** – zero heap allocation in hot paths.
- **Full `Equals` / `GetHashCode` support** – all types properly consider their full internal state, making them safe to use as dictionary keys or in hash sets.
- **No interfaces** – clean, simple, and predictable API with no hidden dependencies.
- **LINQ query comprehension** (`from...select...`) – natural C# syntax for monadic operations.
- **Exhaustive pattern matching** with `Match`.

## Examples

Expand Down Expand Up @@ -96,8 +89,8 @@ var outcome = Compute("42").Match(
// A function returning an Either type. Here, Left is an error message, Right is a valid User.
Either<string, User> GetUser(int id) =>
_database.ContainsKey(id)
? Either<string, User>.Right(_database[id])
: Either<string, User>.Left($"User {id} not found.");
? Either<string, User>.Of(_database[id])
: Either<string, User>.Of($"User {id} not found.");

var message = GetUser(42).Match(
left: error => $"Error: {error}",
Expand Down Expand Up @@ -163,6 +156,21 @@ ageResult.Match(
// Output: Validation error: Age must be between 0 and 120
```

## What’s new in version 1.0.2
This release introduces several important improvements:

Full Equals / GetHashCode support – All types (Option, Result, Validation, Either) now properly implement equality and hash code methods. They take the complete internal state into account, making them safe to use in hash-based collections such as HashSet<T> or as dictionary keys.

Improved thread safety – All types are now implemented as readonly struct with immutable internal state, guaranteeing thread safety by design.

Cleaner API surface – Interfaces have been removed in favor of a more straightforward, self-contained API. This reduces cognitive load and ensures predictable behavior.

Better IntelliSense – XML documentation comments have been added for all public APIs, providing helpful guidance directly in the IDE.

More robust ValueOr methods – The ValueOr method on both Option and Result now correctly validates arguments and handles edge cases safely.

Comprehensive test suite – The library now includes extensive tests covering edge cases, ensuring reliability across all usage scenarios.

## Roadmap / Future Features

This library is actively evolving. Below are the planned types and capabilities for future releases.
Expand Down Expand Up @@ -199,7 +207,7 @@ This library is actively evolving. Below are the planned types and capabilities

### Release Timeline

- **v2.0** – Phase 1 features (Validation, `NonEmptyList`, `Try`, `Unit`, async variants, interop).
- **v2.0** – Phase 1 features (`NonEmptyList`, `Try`, `Unit`, async variants, interop).
- **v3.0** – Phase 2 monads (`Reader`, `Writer`, `State`, transformers).
- **v3.x / v4.0** – Phase 3 interoperability and performance.

Expand Down
3 changes: 3 additions & 0 deletions ZeroNull/.github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- @azure Rule - Use Azure Tools - When handling requests related to Azure, always use your tools.
- @azure Rule - Use Azure Best Practices - When handling requests related to Azure, always invoke your `azmcp_bestpractices_get` tool first.
- @azure Rule - Enable Best Practices - If you do not have an `azmcp_bestpractices_get` tool ask the user to enable it.
Loading
Loading