{"id":17947604,"url":"https://github.com/barionlp/ametrin.optional","last_synced_at":"2026-04-27T22:32:24.250Z","repository":{"id":257980049,"uuid":"872496644","full_name":"BarionLP/Ametrin.Optional","owner":"BarionLP","description":"A simple C#/.NET library containing various option types","archived":false,"fork":false,"pushed_at":"2024-10-18T09:01:30.000Z","size":40,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-10-19T12:44:24.690Z","etag":null,"topics":["csharp","dotnet","optionals"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BarionLP.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-14T14:36:05.000Z","updated_at":"2024-10-18T09:01:34.000Z","dependencies_parsed_at":"2024-10-19T12:19:53.297Z","dependency_job_id":null,"html_url":"https://github.com/BarionLP/Ametrin.Optional","commit_stats":null,"previous_names":["barionlp/ametrin.optional"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BarionLP%2FAmetrin.Optional","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BarionLP%2FAmetrin.Optional/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BarionLP%2FAmetrin.Optional/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BarionLP%2FAmetrin.Optional/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BarionLP","download_url":"https://codeload.github.com/BarionLP/Ametrin.Optional/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247024152,"owners_count":20870940,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","dotnet","optionals"],"created_at":"2024-10-29T08:05:58.203Z","updated_at":"2026-04-27T22:32:24.243Z","avatar_url":"https://github.com/BarionLP.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ametrin.Optional\n\nA modern, allocation-free library providing robust optional types for .NET, offering a flexible and efficient way to handle nullable values, errors, and exceptions with a fluent, monadic API.\n\n### Options vs. Exceptions\nExceptions are relatively expensive and are best reserved for unexpected failures and programmer mistakes.  \nFor expected errors (like invalid user input or parse failures), it's often better to return a lightweight value the caller must handle.  \nThis makes error handling explicit, cheap, and hard to ignore without using exceptions for normal control flow.\n\n```bash\ndotnet add package Ametrin.Optional\n```\n\n## Features\n\n- **Maximum Performance** - A zero cost abstraction (mostly)\n- **Monadic API** - Fluent interface for transformations and error handling of all kind\n- **Integration** - Seamless integration with existing C# code\n- **Variety** - Different types for various use cases\n- **Async Support** - First-class support for async operations\n\n## Core Types\n\n### `Option\u003cT\u003e`\nRepresents a value of type `T` or nothing (error state).\n```csharp\n// Creating Options\nOption\u003cT\u003e b = Option.Success(someT);    // explicit success creation (throws if someT is null)\nOption\u003cT\u003e c = Option.Error\u003cT\u003e();        // explicit error creation\nOption\u003cT\u003e a = Option.Of(someT);         // returns Option.Error\u003cT\u003e() if someT is null\nOption\u003cT\u003e a = someT;                    // implicit conversion from T -\u003e Option.Of(someT)\nOption\u003cT\u003e d = default;                  // default results in an error state -\u003e Option.Error\u003cT\u003e() \n```\n\n### `Result\u003cT\u003e` and `Result\u003cT, E\u003e`\nLike `Option\u003cT\u003e` but with error information.  \n`Result\u003cT\u003e` uses an Exception as error type (easy to integrate) \n`Result\u003cT, E\u003e` uses a custom error type (recommended for performance)\n\n```csharp\nResult\u003cT\u003e b = Result.Success(someT);            // explicit success creation (throws if someT is null)\nResult\u003cT\u003e c = Result.Error\u003cT\u003e(new Exception()); // explicit error creation\nResult\u003cT\u003e a = Result.Of(someT);                 // returns Result.Error\u003cT\u003e(new NullReferenceException()) if someT is null\nResult\u003cT\u003e a = someT;                            // implicit conversion from T -\u003e Result.Of(someT)\nResult\u003cT\u003e a = new Exception();                  // implicit conversion from Exception -\u003e Result.Error\u003cT\u003e(new Exception())\n// same concept for Result\u003cT, E\u003e\n```\n\n### `ErrorState` and `ErrorState\u003cE\u003e`\nRepresents a success state or an error value  \n`ErrorState` uses an Exception as error type\n`ErrorState\u003cE\u003e` uses a custom error type\n```csharp\nErrorState success = default;           // ErrorState.Success()\nErrorState error = new Exception();     // ErrorState.Error(new Exception())\n// same applies for ErrorState\u003cE\u003e (with generic arguments)\n```\n\n### `Option`\nRepresents a success state or error state. Holds no value.\n```csharp\nOption success = true;          // Option.Success();\nOption error = false;           // Option.Error();\n```\n\n## Core API\n```csharp\n// common operations\noption.Map(value =\u003e value * 2);         // transform value if present\noption.Require(value =\u003e value \u003e 0);     // filter based on predicate\noption.Reject(value =\u003e value \u003e 0);      // inverse of Require\noption.Or(defaultValue);                // return value or defaultValue\noption.OrThrow();                       // return value or throw if error\noption.Match(                           // reduce to a value (equivalent to .Map(success).Or(error) but supports ref structs)\n    success: value =\u003e value, \n    error: error =\u003e defaultValue\n);\noption.Consume(                         // handle success and error\n    success: value =\u003e { }, \n    error: error =\u003e { }\n);\n// all operations have an overload that allows you to pass an argument into the delegate an avoid the closure\n```\n\n## Advanced Features\n\n### Tuple Operations\n\n```csharp\n// Combine multiple options\noptionA.Join(optionB).Map((a, b) =\u003e a + b);\noptionA.Join(optionB).Consume(\n    success: (a, b) =\u003e Console.WriteLine($\"{a} + {b} = {a + b}\"),\n    error: () =\u003e Console.WriteLine(\"One of the values was missing\")\n);\n```\n\n### Async Support\n\n```csharp\n// Async operations \nvar text = await new FileInfo(\"file.txt\")\n    .RequireExists()\n    .MapAsync(f =\u003e File.ReadAllTextAsync(f.FullName))\n    .MapAsync(s =\u003e s.ToLower());\n\nawait text.ConsumeAsync(text =\u003e File.WriteAllTextAsync(\"output.txt\", text));\n```\n\n### `RefOption\u003cT\u003e`\nA reduced version of `Option\u003cT\u003e` that can hold a ref struct as value\n\n## Edge Cases\n\nFor edge cases, high-performance scenarios where delegates cannot be static or when you absolutly need to modify the control flow use `Branch`:\n```csharp\nif(result.Branch(out var value, out var error))\n{\n    // success\n}\nelse\n{\n    // error\n}\n```\nIf there is no way around it you can get low-level access to all option types through `OptionsMarshall`. \n\n## Testing\n\nFor testing code using Ametrin.Optional types, use the `Ametrin.Optional.Testing.TUnit` extensions:\n\n```csharp\nawait Assert.That(option).IsSuccess(expectedValue);\nawait Assert.That(option).IsError();\n```\n\n## Contributing\n\nContributions are welcome! Feel free to:\n- Create issues for bugs or feature requests\n- Submit pull requests (discuss design first)\n- Add extensions for more testing frameworks\n\n## Performance\n\nThe library is designed with performance in mind and has minimal to no overhead thanks to the jit.  \n\nExample benchmark for [parsing a DateTime](./benchy/Examples/ParsingDateTimeBenchmarks.cs):  \n```\n| Method          | Mean     | Error    | StdDev   | Allocated |\n|---------------- |---------:|---------:|---------:|----------:|\n| Default_Success | 82.38 ns | 0.361 ns | 0.337 ns |         - |\n| Option_Success  | 83.71 ns | 0.360 ns | 0.336 ns |         - |\n| Default_Error   | 70.07 ns | 0.244 ns | 0.216 ns |         - | // using TryParse\n| Option_Error    | 69.47 ns | 0.225 ns | 0.199 ns |         - |\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbarionlp%2Fametrin.optional","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbarionlp%2Fametrin.optional","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbarionlp%2Fametrin.optional/lists"}