|
| 1 | +# Implicit vs. Explicit Conversions |
| 2 | + |
| 3 | +This document outlines the design decisions regarding implicit and explicit conversions for the `Option<T>` and `NullableOption<T>` types. |
| 4 | + |
| 5 | +## Summary |
| 6 | + |
| 7 | +| Conversion | Type | Status | Rationale | |
| 8 | +| :--- | :--- | :--- | :--- | |
| 9 | +| `T` → `Option<T>` | Implicit | ✅ Allowed | Always safe; never throws. | |
| 10 | +| `Option<T>` → `T` | Explicit | ⚠️ Restricted | Unsafe; throws on `None`. | |
| 11 | + |
| 12 | +## Implicit Conversions (`T` → `Option<T>`) |
| 13 | + |
| 14 | +We allow implicit conversion from a value `T` to an `Option<T>` (or `NullableOption<T>`). |
| 15 | + |
| 16 | +```csharp |
| 17 | +Option<int> opt = 42; // Implicitly creates Option.Some(42) |
| 18 | +``` |
| 19 | + |
| 20 | +### Reasoning |
| 21 | + |
| 22 | +1. **Safety**: Wrapping a value in an Option is a safe operation that will never throw an exception (assuming the constructor validation passes, e.g., non-null for `Option<T>`). |
| 23 | +2. **Convenience**: It allows for cleaner syntax when returning values from methods defined to return `Option<T>`. |
| 24 | +3. **Precedent**: This mirrors the behavior of `Nullable<T>` in C# (e.g., `int? x = 5;`). |
| 25 | + |
| 26 | +## Explicit Conversions (`Option<T>` → `T`) |
| 27 | + |
| 28 | +We **require** an explicit cast when converting from an `Option<T>` back to its underlying type `T`. |
| 29 | + |
| 30 | +```csharp |
| 31 | +Option<int> opt = Option.None<int>(); |
| 32 | + |
| 33 | +// ❌ Compile Error |
| 34 | +int value = opt; |
| 35 | + |
| 36 | +// ✅ Compiles, but may throw at runtime |
| 37 | +int value = (int)opt; |
| 38 | +``` |
| 39 | + |
| 40 | +### Rationale for Explicit Requirement |
| 41 | + |
| 42 | +#### 1. Violation of Design Guidelines |
| 43 | + |
| 44 | +Microsoft's [Framework Design Guidelines](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/operator-overloads) explicitly state: |
| 45 | + |
| 46 | +> **DO NOT** throw exceptions from implicit casts. |
| 47 | +
|
| 48 | +Converting a `None` state to `T` is impossible without providing a default value or throwing an exception. Since the cast operator cannot accept a default value argument, it must throw `InvalidOperationException` when the option is `None`. Therefore, making this conversion implicit would violate standard .NET design patterns. |
| 49 | + |
| 50 | +#### 2. Safety and Intent |
| 51 | + |
| 52 | +The primary purpose of `Option<T>` is to force the developer to handle the "missing value" case. |
| 53 | + |
| 54 | +* **Explicit Cast**: Signals "I know this might fail, but I am asserting a value exists." |
| 55 | +* **Implicit Cast**: Hides the potential failure. A simple assignment `T x = option;` looking perfectly safe could crash the application at runtime. |
| 56 | + |
| 57 | +#### 3. Consistency with `Nullable<T>` |
| 58 | + |
| 59 | +`Option<T>` is designed to be a more expressive counterpart to `Nullable<T>`. |
| 60 | + |
| 61 | +* `Nullable<T>` requires an explicit cast to extract the value: |
| 62 | + |
| 63 | + ```csharp |
| 64 | + int? n = null; |
| 65 | + int i = (int)n; // Throws InvalidOperationException |
| 66 | + ``` |
| 67 | + |
| 68 | +* Making `Option<T>` implicit would break the mental model established by `Nullable<T>` and confuse developers expecting standard C# behavior. |
| 69 | + |
| 70 | +#### 4. "Footgun" Prevention |
| 71 | + |
| 72 | +If the conversion were implicit, it would be easy to accidentally pass an `Option<T>` to a method expecting `T`, leading to runtime crashes that are hard to spot during code review. |
| 73 | + |
| 74 | +```csharp |
| 75 | +// If implicit conversion were allowed: |
| 76 | +public void Process(string input) { ... } |
| 77 | + |
| 78 | +Option<string> maybeName = Option.None<string>(); |
| 79 | +Process(maybeName); // Looks safe, compiles, but crashes at runtime! |
| 80 | +``` |
| 81 | + |
| 82 | +By requiring an explicit cast (or better, using `.Or()`, `.OrDefault()`, or `.Match()`), we ensure the developer consciously handles the control flow. |
0 commit comments