But what can we do about it? To start let's review the meaning of null values ...

Modeling optional results

Finding Customers

Finding operations are very common. Given a Customer class, a Find method could look like this:

1

public Customer Find(Query query) ;

Now what happens when the customer can not be found? Possible options are:

Throw an exception: Why though? Where is the exceptional case? Trying to find a Customer has the possible scenario of not beign found.

Return null to mean nothing was found. But are we positive we are getting a null for that reason and not other? And what can we do with the null value after?

Return a NullObject that represents Customer null value. That could work to show some of the customer's data, if we expect strings or something similar. But for most cases this won't be enough.

Parsing Integers

In C# you can use Int32.parse or Int32.tryParse to do the job. The former throws an Exception when the string can not be parsed into an int and the later returns a Bool indicating if the operation succeeded using an out parameter for the value.

The first approach is not that intuitive. I want to get a result, not to catch an exception.

The second one with the boolean result seems to go in the right direction but having an out parameter complicates things, and makes it hard to understand and hard to pass to another function, etc.

Optional values

F# has a very simple way to deal with this by creating a Discriminated Union with only two values:

123

typeOption<'T> = | Some of'T | None

Now finding customers has a very clear interface:

1

let tryFindCustomer (q: query) : Option<Customer>

Parse clearly can succeed giving the parsed result or fail, therefore the result is Optional.

All parameters are present, then the result is Success with the output of findCustomers.

And four unhappy paths:

count is not present, then the maybe builder does shortcircuit to None and getOrElse returns an Error.

city is not present, then the maybe builder does shortcircuit to None and getOrElse returns an Error.

country is not present, then the maybe builder does shortcircuit to None and getOrElse returns an Error.

count is present, but can not be parsed then ... shortcircuit ... and Error.

The let! is doing the unboxing from Option to the actual type, and when any of the expressions has the value None then the builder does the shortcircuit and returns None as result.

Applicative Style

Another way to write the same concept (sometimes a bit more clear) is to use the Applicative style by using operators that represent the operations that we already are using that also apply shortcircuit when possible.

Now we need to apply the boxed function to a boxed value, and for that we can use the operator <*> that takes a boxed function and a boxed value and returns the boxed version of applying the function to the value.

1

findCustomers <!> count <*> city ... // partial application of the function to city

In this case we have two more parameters so the full version would be: