Skip to content

Commit 8ade153

Browse files
committed
interfaces removed, all types implemting iequatable
1 parent ef45583 commit 8ade153

15 files changed

+353
-249
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ var optionNone = Option<int>.None();
3535
Options are commonly used when a operation might not return a value.
3636

3737
```csharp
38-
public IOption<int> TryFind(IEnumerable<int> numbers, Func<int, bool> predicate) =>
38+
public Option<int> TryFind(IEnumerable<int> numbers, Func<int, bool> predicate) =>
3939
numbers.FirstOrDefault(predicate).ToOption();
4040
```
4141

src/Danom/Option/Option.cs

+36-33
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,18 @@ namespace Danom;
55
/// using nulls, and allows for more expressive code with exhaustive matching.
66
/// </summary>
77
/// <typeparam name="T"></typeparam>
8-
public interface IOption<T>
9-
{
10-
bool IsSome { get; }
11-
bool IsNone { get; }
12-
U Match<U>(Func<T, U> some, Func<U> none);
13-
IOption<U> Bind<U>(Func<T, IOption<U>> bind);
14-
IOption<U> Map<U>(Func<T, U> map);
15-
T DefaultValue(T defaultValue);
16-
T DefaultWith(Func<T> defaultWith);
17-
IOption<T> OrElse(IOption<T> ifNone);
18-
IOption<T> OrElseWith(Func<IOption<T>> ifNoneWith);
19-
}
20-
21-
/// <inheritdoc cref="IOption{T}" />
228
public readonly struct Option<T>
23-
: IOption<T>
9+
: IEquatable<Option<T>>
2410
{
2511
private readonly T? _some = default;
2612

2713
private Option(T t)
2814
{
29-
_some = t;
30-
IsSome = true;
15+
if (t is not null)
16+
{
17+
_some = t;
18+
IsSome = true;
19+
}
3120
}
3221

3322
/// <summary>
@@ -58,8 +47,8 @@ public U Match<U>(Func<T, U> some, Func<U> none) =>
5847
/// <typeparam name="U"></typeparam>
5948
/// <param name="bind"></param>
6049
/// <returns></returns>
61-
public IOption<U> Bind<U>(
62-
Func<T, IOption<U>> bind) =>
50+
public Option<U> Bind<U>(
51+
Func<T, Option<U>> bind) =>
6352
Match(bind, Option<U>.None);
6453

6554
/// <summary>
@@ -68,7 +57,7 @@ public IOption<U> Bind<U>(
6857
/// <typeparam name="U"></typeparam>
6958
/// <param name="map"></param>
7059
/// <returns></returns>
71-
public IOption<U> Map<U>(
60+
public Option<U> Map<U>(
7261
Func<T, U> map) =>
7362
Bind(x => Option<U>.Some(map(x)));
7463

@@ -95,17 +84,17 @@ public T DefaultWith(
9584
/// </summary>
9685
/// <param name="ifNone"></param>
9786
/// <returns></returns>
98-
public IOption<T> OrElse(
99-
IOption<T> ifNone) =>
87+
public Option<T> OrElse(
88+
Option<T> ifNone) =>
10089
Match(Option<T>.Some, () => ifNone);
10190

10291
/// <summary>
10392
/// Return Option if it is Some, otherwise evaluate ifNoneWith.
10493
/// </summary>
10594
/// <param name="ifNoneWith"></param>
10695
/// <returns></returns>
107-
public IOption<T> OrElseWith(
108-
Func<IOption<T>> ifNoneWith) =>
96+
public Option<T> OrElseWith(
97+
Func<Option<T>> ifNoneWith) =>
10998
Match(Option<T>.Some, ifNoneWith);
11099

111100

@@ -114,37 +103,37 @@ public IOption<T> OrElseWith(
114103
/// </summary>
115104
/// <param name="value"></param>
116105
/// <returns></returns>
117-
public static IOption<T> Some(T value) =>
106+
public static Option<T> Some(T value) =>
118107
new Option<T>(value);
119108

120109
/// <summary>
121110
/// Creates Option with the specified value wrapped in a completed Task.
122111
/// </summary>
123112
/// <param name="value"></param>
124113
/// <returns></returns>
125-
public static Task<IOption<T>> SomeAsync(T value) =>
114+
public static Task<Option<T>> SomeAsync(T value) =>
126115
Task.FromResult(Some(value));
127116

128117
/// <summary>
129118
/// Creates a new Option with the value of the awaited Task.
130119
/// </summary>
131120
/// <param name="value"></param>
132121
/// <returns></returns>
133-
public static async Task<IOption<T>> SomeAsync(Task<T> value) =>
122+
public static async Task<Option<T>> SomeAsync(Task<T> value) =>
134123
Some(await value);
135124

136125
/// <summary>
137126
/// Creates a new Option with no value.
138127
/// </summary>
139128
/// <returns></returns>
140-
public static IOption<T> None() =>
129+
public static Option<T> None() =>
141130
new Option<T>();
142131

143132
/// <summary>
144133
/// Creates a new Option with no value wrapped in a completed Task.
145134
/// </summary>
146135
/// <returns></returns>
147-
public static Task<IOption<T>> NoneAsync() =>
136+
public static Task<Option<T>> NoneAsync() =>
148137
Task.FromResult(None());
149138

150139
public static bool operator ==(Option<T> left, Option<T> right) =>
@@ -154,10 +143,24 @@ public static Task<IOption<T>> NoneAsync() =>
154143
!(left == right);
155144

156145
public override bool Equals(object? obj) =>
157-
_some is not null && obj is not null && _some.Equals(obj);
146+
obj is Option<T> o && Equals(o);
158147

159-
public override int GetHashCode()
160-
=> _some is null ? 0 : _some.GetHashCode();
148+
public readonly bool Equals(Option<T> other) =>
149+
Match(
150+
some: x1 =>
151+
other.Match(
152+
some: x2 => x1 is not null && x2 is not null && x2.Equals(x1),
153+
none: () => false),
154+
none: () =>
155+
other.Match(
156+
some: _ => false,
157+
none: () => true)
158+
);
159+
160+
public override int GetHashCode() =>
161+
Match(
162+
some: x => x is null ? 0 : x.GetHashCode(),
163+
none: () => 0);
161164

162165
public override string ToString() =>
163166
Match(
@@ -178,7 +181,7 @@ public static class OptionActionExtensions
178181
/// <param name="option"></param>
179182
/// <param name="some"></param>
180183
/// <param name="none"></param>
181-
public static void Match<T>(this IOption<T> option, Action<T> some, Action none)
184+
public static void Match<T>(this Option<T> option, Action<T> some, Action none)
182185
{
183186
if (option.ToNullable() is T t)
184187
{

src/Danom/Option/OptionNullable.cs

+17-17
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
namespace Danom;
22

33
/// <summary>
4-
/// Contains extension methods for <see cref="IOption{T}"/> that allow for
4+
/// Contains extension methods for <see cref="Option{T}"/> that allow for
55
/// converting between nullable types and options.
66
/// </summary>
77
public static class OptionNullableExtensions
@@ -12,7 +12,7 @@ public static class OptionNullableExtensions
1212
/// <typeparam name="T"></typeparam>
1313
/// <param name="x"></param>
1414
/// <returns></returns>
15-
public static IOption<T> ToOption<T>(this T? x) =>
15+
public static Option<T> ToOption<T>(this T? x) =>
1616
x is not null && (!Equals(x, default(T))) ? Option<T>.Some(x) : Option<T>.None();
1717

1818
/// <summary>
@@ -21,15 +21,15 @@ public static IOption<T> ToOption<T>(this T? x) =>
2121
/// <typeparam name="T"></typeparam>
2222
/// <param name="x"></param>
2323
/// <returns></returns>
24-
public static IOption<T> ToOption<T>(this T? x) where T : struct =>
24+
public static Option<T> ToOption<T>(this T? x) where T : struct =>
2525
(x is T t) ? Option<T>.Some(t) : Option<T>.None();
2626

2727
/// <summary>
2828
/// Converts a nullable string to an option.
2929
/// </summary>
3030
/// <param name="x"></param>
3131
/// <returns></returns>
32-
public static IOption<string> ToOption(this string? x) =>
32+
public static Option<string> ToOption(this string? x) =>
3333
x is not null && !string.IsNullOrWhiteSpace(x) ? Option<string>.Some(x) : Option<string>.None();
3434

3535
/// <summary>
@@ -38,102 +38,102 @@ public static IOption<string> ToOption(this string? x) =>
3838
/// <typeparam name="T"></typeparam>
3939
/// <param name="option"></param>
4040
/// <returns></returns>
41-
public static T? ToNullable<T>(this IOption<T> option) =>
41+
public static T? ToNullable<T>(this Option<T> option) =>
4242
option.Match(some: x => x, none: () => default!);
4343

4444
/// <summary>
4545
/// Converts a char option to a nullable value.
4646
/// </summary>
4747
/// <param name="option"></param>
4848
/// <returns></returns>
49-
public static char? ToNullable(this IOption<char> option) =>
49+
public static char? ToNullable(this Option<char> option) =>
5050
option.Match(x => new char?(x), () => null);
5151

5252
/// <summary>
5353
/// Converts a bool option to a nullable value.
5454
/// </summary>
5555
/// <param name="option"></param>
5656
/// <returns></returns>
57-
public static bool? ToNullable(this IOption<bool> option) =>
57+
public static bool? ToNullable(this Option<bool> option) =>
5858
option.Match(x => new bool?(x), () => null);
5959

6060
/// <summary>
6161
/// Converts a byte option to a nullable value.
6262
/// </summary>
6363
/// <param name="option"></param>
6464
/// <returns></returns>
65-
public static byte? ToNullable(this IOption<byte> option) =>
65+
public static byte? ToNullable(this Option<byte> option) =>
6666
option.Match(x => new byte?(x), () => null);
6767

6868
/// <summary>
6969
/// Converts a short option to a nullable value.
7070
/// </summary>
7171
/// <param name="option"></param>
7272
/// <returns></returns>
73-
public static short? ToNullable(this IOption<short> option) =>
73+
public static short? ToNullable(this Option<short> option) =>
7474
option.Match(x => new short?(x), () => null);
7575

7676
/// <summary>
7777
/// Converts a ushort option to a nullable value.
7878
/// </summary>
7979
/// <param name="option"></param>
8080
/// <returns></returns>
81-
public static int? ToNullable(this IOption<int> option) =>
81+
public static int? ToNullable(this Option<int> option) =>
8282
option.Match(x => new int?(x), () => null);
8383

8484
/// <summary>
8585
/// Converts a uint option to a nullable value.
8686
/// </summary>
8787
/// <param name="option"></param>
8888
/// <returns></returns>/
89-
public static long? ToNullable(this IOption<long> option) =>
89+
public static long? ToNullable(this Option<long> option) =>
9090
option.Match(x => new long?(x), () => null);
9191

9292
/// <summary>
9393
/// Converts a ulong option to a nullable value.
9494
/// </summary>
9595
/// <param name="option"></param>
9696
/// <returns></returns>
97-
public static decimal? ToNullable(this IOption<decimal> option) =>
97+
public static decimal? ToNullable(this Option<decimal> option) =>
9898
option.Match(x => new decimal?(x), () => null);
9999

100100
/// <summary>
101101
/// Converts a double option to a nullable value.
102102
/// </summary>
103103
/// <param name="option"></param>
104104
/// <returns></returns>
105-
public static double? ToNullable(this IOption<double> option) =>
105+
public static double? ToNullable(this Option<double> option) =>
106106
option.Match(x => new double?(x), () => null);
107107

108108
/// <summary>
109109
/// Converts a float option to a nullable value.
110110
/// </summary>
111111
/// <param name="option"></param>
112112
/// <returns></returns>
113-
public static float? ToNullable(this IOption<float> option) =>
113+
public static float? ToNullable(this Option<float> option) =>
114114
option.Match(x => new float?(x), () => null);
115115

116116
/// <summary>
117117
/// Converts a decimal option to a nullable value.
118118
/// </summary>
119119
/// <param name="option"></param>
120120
/// <returns></returns>
121-
public static Guid? ToNullable(this IOption<Guid> option) =>
121+
public static Guid? ToNullable(this Option<Guid> option) =>
122122
option.Match(x => new Guid?(x), () => null);
123123

124124
/// <summary>
125125
/// Converts a DateTime option to a nullable value.
126126
/// </summary>
127127
/// <param name="option"></param>
128128
/// <returns></returns>
129-
public static DateTime? ToNullable(this IOption<DateTime> option) =>
129+
public static DateTime? ToNullable(this Option<DateTime> option) =>
130130
option.Match(x => new DateTime?(x), () => null);
131131

132132
/// <summary>
133133
/// Converts a DateTimeOffset option to a nullable value.
134134
/// </summary>
135135
/// <param name="option"></param>
136136
/// <returns></returns>
137-
public static DateOnly? ToNullable(this IOption<DateOnly> option) =>
137+
public static DateOnly? ToNullable(this Option<DateOnly> option) =>
138138
option.Match(x => new DateOnly?(x), () => null);
139139
}

0 commit comments

Comments
 (0)