vkhorikov/CSharpFunctionalExtensions

Overload for Option.Unwrap that takes a function

guythetechie opened this issue · 4 comments

Let's say we have the following situation:

 // Get parent's favorite child, returning None if they lied about being neutral :)
Maybe<Child> GetFavoriteChild(Parent parent) => ...

// Expensive computation to predict a likely favorite
Child PredictFavoriteChild() => ... 

// Option 1
Child WhoGetsTheLastCookie(Parent parent)
{
  var defaultChild = PredictFavoriteChild(); // Expensive computation is always performed
  return GetFavoriteChild(parent).Unwrap(defaultChild );
}

// Option 2 - currently works just fine, just not as clean as Option 3 (IMO)
Child WhoGetsTheLastCookie(Parent parent)
{
 var childOption = GetFavoriteChild(customer);
 return childOption .HasValue ? childOption .Value : PredictFavoriteChild();
}

// Option 3 - proposed Unwrap overload
Child WhoGetsTheLastCookie(Parent parent) =>
  GetFavoriteChild(customer)
    .Unwrap(PredictFavoriteChild);

In F#, there is a defaultWith function that looks like this:

Option.defaultWith : (unit -> 'T) -> ('T option):  'T

I believe this could fit well as an Unwrap overload:

// Proposed new overload
public static T Unwrap<T>(this Maybe<T> maybe, Func<T> compensator)

// Existing Unwrap definitions for reference
public static T Unwrap<T>(this Maybe<T> maybe, T defaultValue = default(T))
public static K Unwrap<T, K>(this Maybe<T> maybe, Func<T, K> selector, K defaultValue = default(K))

I would find value in adding this overload, but was wondering whether it's generally useful enough to add to the library. Happy to create a PR if necessary.

Thanks!

There is already a discussion on such feature (as a GetValueOrDefault) in #312

Thanks for the info. I do see a difference between my proposal and the discussion. In the discussion, GetValueOrDefault would take a default value as a parameter: GetValueOrDefault<T>(T default). I propose that it also takes a function returning a default value: GetValueOrDefault<T>(Func<T> selector).

Happy to close this and fold it into the existing thread.

Yeah, I think this overload would be useful, and maybe GetValueOrDefault<T>(Func<Task<T>> selector) as well. Feel free to add a suggestion to that issue.

I also agree. GetValueOrDefault<T>(Func<Task<T>> selector) is a nice addition.