0

Consider the following classes...

public abstract class Option<T>
{
    public T Value { get; protected set; }
}

public sealed class Some<T> : Option<T>
{
    public Some(T value)
    {
        Value = value;
    }
}

public sealed class None<T> : Option<T>
{
}

public sealed class Error<T> : Option<T>
{
    /*
    * Error related information would go here.
    */
}

The Some<T>, None<T>, and Error<T> classes would be used to represent the three possible kinds of result from a method (data access or otherwise).

We'd have a method similar to the following example that would return the base Option<T> type in order to allow any of the possible kinds of result to come from the method.

public Option<string> GetSomeContrivedResult()
{
    /*
    * Method implementation here...
    */
}

The idea would be to have a Rosyln analyzer enforce the handling of the three possible kinds of result. So for example, the following code would be in error because it doesn't handle each of the possible kinds of result from the GetSomeContrivedResult method.

public void ContrivedMethod()
{
    var result = GetSomeContrivedResult(); // Error would be expected here.

    Console.WriteLine(result.Value);
}

The following example would be "in compliance" with the "rule" that all three possible kinds of result are handled.

public void ContrivedMethod()
{
    var result = GetSomeContrivedResult();

    switch(result)
    {
        case Some<string> s:
            Console.WriteLine(s.Value);
            break;

        case None<string> n:
            Console.WriteLine("Nothing here.");
            break;

        case Error<string> e:
            Console.WriteLine("Some kind of non-exception error happened.");
            break;
    } 
}

I've been looking into creating a Roslyn analyzer that would raise an error or warning in the event that the Option<T> wasn't "correctly" handled, but as of yet I'm having trouble figuring out if what I want to do is even possible.

In terms of creating an analyzer to do this kind of analysis where should I start?

1 Answer 1

2

I think you're overcomplicating it.

Simply make Value private, and require the consumer to use an inbuilt method (might I suggest Select) In order to extract the value, since Option is effectively the same thing as a list which can contain at most one element. Otherwise you can use pattern matching to cast to the correct type.

In most languages which use Monads such as these, you would typically use a seperate type for Error<T> and Option<T>, because not every function which may or may not return a result can also return an error, and not every function which could return an error would otherwise ever not return a result. Consider:

public Error<T> Divide(int x, int y) => x / y;

This function can return an error if y is 0, but otherwise you should never get a None back, so how would you even handle that case?

The real issue you could run into with C# is that a function marked as returning an Option<T> actually returns a null, unless you make sure you have nullable reference types turned on.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.