Classical C# versus pure F#

Adopting a functional programming style should not be like following a new fashion trend, particularly when a well established traditional approach can meet what business demands.

programming

This is the classical C# version of “Pure times in F#“. It is not a literal translation, but only Proof of Concept.

First step, we have to define an interface: the macro design, the general idea.

    public interface IPoll<TIn, TOut>
    {
        Task<TOut> poll(TIn input);
    }

    public class PollingReturn<TOut, TError>
    {
        public TimeSpan elapsed;
        public bool success;
        public TOut output;
        public TError error;
    }

    public interface IMeasure<TIn, TOut, TError>
    {
        Task<PollingReturn<TOut, TError>> measure(IPoll<TIn, TOut> poll,
            TIn input);
    }
 

Then we implement the polling class: an async task

    public class PollImpl : IPoll<int, string>
    {
        async Task<string> IPoll<int, string>.poll(int milliseconds)
        {
            var timer = new Stopwatch();
            timer.Start();
            await Task.Delay(milliseconds);
            timer.Stop();
            return "awaited " + milliseconds + " ms in "
                + timer.ElapsedMilliseconds + " ms";
        }
    }

and the measurement class: a stop-watch wrapper

        async Task<PollingReturn<string, Exception>> IMeasure<int, string, Exception>.measure(IPoll<int, string> polling,
            int input)
        {
            var timer = new Stopwatch();
            timer.Start();
            var ret = new PollingReturn<string, Exception>();
            var pollingTask = polling.poll(input);
            try
            {
                ret.output = await pollingTask;
                ret.success = true;
            }
            catch (Exception exc)
            {
                ret.error = exc;
            }
            timer.Stop();
            ret.elapsed = timer.Elapsed;
            return ret;
        }

Finally we define the stats utility

        public class Stats
        {
            int totDuration = 0;
            int totEvents = 0;
            double mean = 0;
            double devStd = 0;

            List<int> results = new List<int>();

            public void addEvent(int milliseconds)
            {
                totEvents++;
                totDuration += milliseconds;
                results.Add(milliseconds);
                mean = results.Average();
                devStd = Math.Sqrt(
                results.Select(r => (r - mean) * (r - mean)).Sum()
                / totEvents
                );
            }

            public double average()
            {
                return mean;
            }

            public double stdDev()
            {
                return devStd;
            }

            public bool StopAfter(int maxMilliSecs, double defEstimate)
            {
                if (totEvents == 0)
                {
                    return defEstimate >= maxMilliSecs;
                }
                return totDuration + mean + devStd > maxMilliSecs;
            }
        }

and a test case

        static async Task<Stats> TestMeasure(IPoll<int,string> polling,
            IMeasure<int, string, Exception> measuring, Random rnd)
        {
            var stats = new Stats();
            for (int i = 0; i < 20; i++)
            {
                if (stats.StopAfter(3000, 250))
                {
                    Console.WriteLine("Stopped condition fired at iteration " + i);
                    break;
                }
                var input = rnd.Next(500);
                var measure = await measuring.measure(polling, input);
                Console.WriteLine("Input " + input +
                    " Done after " + measure.elapsed.Milliseconds);
                Console.WriteLine(measure.success ? "success" : "failure");
                Console.WriteLine(measure.success ? measure.output : measure.error.Message);
                stats.addEvent(measure.elapsed.Milliseconds);
            }
            return stats;
        }

Done (github repo)! I may be wrong but the project of a finite state machine seems like a complex, low level implementation of an equivalent, simpler, condition based loop. More generally, I’m not convinced of the issues and the strict definition of non-purity when calling IO functions. What you can see here is that the implementation of the polling interface as actual IO is completely decoupled and furthermore a nice stub has been introduced instead, making possible to test the app with a business oriented approach.

Advertisements

One thought on “Classical C# versus pure F#

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