Just for Fun: a Solution Searching a Problem

Recently I saw a talk about “Railway oriented Programming” by Scott Wlaschin. While he talked about functional programming style to pass the result and the failure from one function to another he did use F# to show a “sum type” (Wikipedia [http://en.wikipedia.org/wiki/Tagged_union] describes it as ”a data structure used to hold a value that could take on several different, but fixed types. Only one of the types can be in use at any one time, and a tag field explicitly indicates which one is in use”).
I thought that would be a very nice thing to have in C#, too – especially with LINQ-statements that are passing IEnumerable around.
I thought about a concrete but simple use case for such a processing and came to a simple array of “string”: { “1”, “12”, “123”, “1234”, null, “12345” }. I want to calculate “100 / (value.Length – 2)” from these strings in a way that I can filter the results that did throw exceptions (in this case “12” will throw a DivideByZeroException) and process all successful calculates value.
The result of some extension methods and some classes is the syntax presented in this unit test:

[TestMethod]
public void PerformingActionsWhileCalculating()
{
    var logger = new ExceptionLogger();
    var counter = new ExecutionCounter();

    var res1 = new[] { "1", "12", "123", "1234", null, "12345" }
        .WithAction<string, int>(counter.Action2)   // this is not optimal, since we need to specify types here
        .WithAction<string, int>(counter.Action3)   // this is not optimal, since we need to specify types here
        .Skip(1)
        .Try(Calculate)                             // here the value is calculated while calling the two actions defined above
        .WhenIs(logger.HandleException)
        .ToArray();

    Assert.AreEqual(5, res1.Count());           // we should have 6 return values
    Assert.AreEqual(5, counter.Count);          // we have only 6 executions of the calculation
    Assert.AreEqual(2, logger.List.Count());    // out list of logs contains two exceptions
    Assert.AreEqual(100, (int)res1[1]);        // check for a successfull result
}

As you can see, the “Select” has been replaced with a “Try” which calls “Calculate” for each member of the array and returns an “IEnumerable<Either<Exception, TRight>>”. “Either” is a struct for values that can have one of two types (in this case either “TRight” or “Exception”).

private static int Calculate(string value)
{
return 100 / (value.Length - 2);
}

Then I call “WhenIs” with the method “HandleException” of “ExceptionLogger”. This method accepts an argument of type “Exception”, so the compiler can use type inference to determine the type to check for. Since the “Either” is either of type “TRight” (in this example the calculation returns an “int”) or an “Exception”, it also can be a “DivideByZeroException” – and that’s what we get for the first element we are passing to “Calculate” (just as a reminder: we skip the first element of the array, so the first element passed to “Calculate” is “12” – calculate divides by the length of the string minus two, what is “0” for the string “12”).
Since the extension method “WithAction” does not simply execute the function provided, but wraps the value together with the function into a new object, the “Skip(1)” will prevent one execution of the function and the function can do things like measuring the duration of the calculation.
I hope you are a bit curious about the implementation, which can be found on GitHub (https://github.com/Interface007/FuncLib). I’m not sure if this implementation is really useful, but I had a lot of fun playing with expressions, generic types, functions of functions, implicit operators etc. It’s like running in nature – you don’t get anything done … but it’s fun.

If you find an interesting problem for this solution, just drop me a comment or a mail – would be very nice to know the code does help somebody to solve a real problem.

Advertisements

3 Responses to Just for Fun: a Solution Searching a Problem

  1. ajdotnet says:

    Since you asked for it… ;o)

    Your “Either” type is essentially a variant. Boost as something similar and may give you some additional hints: http://theboostcpplibraries.com/boost.variant

    Also I stumbled over your code using cast operators (as, is) repeatedly. General recommendation is to use just one cast if it suffices, i.e. use “as” and check for null instead of checking with “is” beforehand.

    More curious is the fact that you are mixing them with explicit casts (https://msdn.microsoft.com/en-us/library/ms173105.aspx). All too many developers are (sadly) not aware of the subtle differences, but cast operators and “real” casts are indeed two different beasts, both, from a language perspective as well as on the IL level.
    With your current implementation (passing an object and a type to the constructor, involving boxing), you don’t profit from these differences, thus I would consider mixing the two a bad practice. While you could rework this to allow you to actually leverage the type conversions provided by casts, the cast would probably be better left to the calling code.

    Also your constructor actually serves two purposes: Passing in untyped information (i.e. type==typeof(object)) and typed information (i.e. type is provided by the caller). If you separate the two demands and provide constructors for TLeft and TRight, code would become simpler, and, as it would avoid boxing, more efficient.

    • Hi Alexander, thanks that you took the time to have a look at it.

      It’s definitely not a “variant”, since, while declaring it as a return parameter or as a variable, you fix exactly two possible types. In contrast to that a variant gets it type while runtime. And this strong typing is exactly the purpose: I want a strong typed variable that can have one of two types I know at design time.

      About “is” and “as”: there are certain conditions where it’s not clear whether the value is a value type (converted via the implicit operator) or a class type, so I need to use “is” because you cannot use “as” with a value type. But I absolutely agree, that the code needs some rework befor you can use it in production or with developers that are not aware of the exact working of “as”, “is” and direct type-casts.

      The ctors may better be private or internal, but hey – this is a pure fun project written in a train while commuting 2 times to work ;-). My main “design goal” was to have a look if I can implement a type that I can really easily use as a return type that can hold the information that there was an exception while processing the value.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Sylvio's Infobox

Aktuelle Themen rund um SQL Server, BI, Windows, ...

Meredith Lewis

Professional Digital Portfolio

Vittorio Bertocci

Just another WordPress.com weblog

ScottGu's Blog

Just another WordPress.com weblog

AJ's blog

Thoughts and informations I think worthwhile to share...

Outlawtrail - .NET Development

Architecture & Design

SDX eXperts Flurfunk

Just another WordPress.com weblog

%d bloggers like this: