Optional
A type-safe implementation of the Optional pattern
In One Line
Null? not Null? Never Matter!
Overview
A type-safe implementation of the Optional pattern, providing elegant null handling and functional programming features for both reference and value types.
The system provides two main structures:
Option<T>for reference typesValueOption<T>for value types
Please read java official document about Optional.
Package Info
display name
AceLand Optional
package name
latest version
1.2.0
namespace
git repository
dependencies
How It Works
Key Features
Type-safe null handling
Functional programming support (Map, Where, Reduce)
Seamless conversion between reference and value types
Fluent interface for method chaining
Extension methods for convenient usage
Full equality comparison support
The system helps eliminate null reference exceptions while providing a clean, functional approach to handling optional values in Unity development.
Create
Option<T> where T : class
ValueOption<T> where T : struct
Get Value
same usage to Option<T> and ValueOption<T>
Advanced Usage
Unity defaultly disable nullable for correct state of game objects, components and assets. However this environment is not friendly for building own system with null result.
Option<T> and ValueOption<T> prevent from returning null in nullable disabled environment.
Here is the common Try-Parse Pattern and solution with Optional.
This is the "old school" but highly optimized way C# handles uncertainty.
Benefits
Zero Allocation: This is the most memory-efficient method possible. It allocates nothing on the heap. It uses the stack for the boolean return and the
outparameter.Standard Library Consistency: Every C# developer knows this pattern. It is the idiomatic way the .NET Framework handles failure (e.g.,
DateTime.TryParse).Control Flow Clarity: It forces you to use an
ifstatement immediately, making it obvious that the operation might fail.
Cons
Cannot Chain Operations (Composition): This is the biggest weakness. You cannot chain methods together.
Bad: You cannot do
TryGet().Map().Filter(). You must write nestedifstatements.
Variable Scope Bleeding: The
outvariable (even with C# 7 inline declaration) "leaks" into the surrounding scope.Example: If you have two
TryGetcalls in the same method, you often have to name variablesdata1anddata2because they conflict.
Async Incompatibility: You cannot use
outparameters inasyncmethods.Impossible:
public async Task<bool> TryGetData(string id, out MyData data)-> Compiler Error.
}
Optional is the modern, functional approach.
Benefits
Composability (Chaining): You can treat the result as a pipeline. You don't need to check
ifat every single step. You can chain.Map,.Where, and.Bindoperations.Async Friendly: You can easily return
Task<Option<T>>. This is the standard way to handle "maybe null" in async/await code.Expression Oriented: It works beautifully with C# switch expressions and pattern matching, allowing for more concise code than
if/elseblocks.Explicit Intent: Returning
Option<MyData>tells the caller "I might not have this" much more clearly than returningMyData?(which implies nullability but doesn't enforce handling it).
Cons
Slight Performance Cost: Even as a
struct, passingOption<T>around involves copying the struct (which is usually larger than a simplebool). However, this cost is negligible for 99% of applications.Non-Standard for Old APIs: Older .NET libraries won't recognize your
Option<T>. You will often have to unwrap it manually to interact with legacy code.Learning Curve: Junior developers familiar only with procedural C# might find
.Mapand.Reduceconfusing compared to a simpleif.
Summary Comparison Table
Feature
bool TryGet(out T)
Option<T>
Performance
π Best (Zero allocation)
β‘ Good (Low allocation struct)
Async / Await
β Impossible
β
Excellent (Task<Option<T>>)
Chaining (LINQ-style)
β Difficult (Nested ifs)
β
Easy (.Map, .Bind)
Code Readability
π Verbose
π Concise
Standard C# Idiom
β Yes
β No (Custom type)
The Verdict: Which one should you use?
Use
Option<T>if:You are writing Async code (e.g., database calls, web APIs).
You have complex business logic where you want to chain transformations (Get data -> Transform it -> Filter it -> Return).
You want to enforce null-safety strictly across your domain.
Use
TryGetif:You are writing a hot path loop (performance critical code running millions of times per second).
You are writing a low-level utility library that needs to feel like standard .NET.
You specifically need to avoid the tiny overhead of struct copying.
Recommendation
For general application development (Web APIs, Business Logic), stick with Option<T>. The ability to handle async correctly and chain operations outweighs the microscopic performance gain of TryGet.
What Should NOT Do ...
Option<T> is not works on all Unity Object type, includes:
GameObject
MonoBehaviour (Component)
Asset types (Texture2D, Sprite, etc)
Unity control the resources of Unity Objects. When an Object is destoryed, it will not be null but return to the resource pool. Unity will release the resource if the resource is no longer be used.
Last updated