Saturday, September 29, 2018

Immutability in .NET

First off, what are immutable objects

Immutable is pretty much a fancy word for unchangeable. In other words, once you create an object it will have the same properties for its entire life. No way to reassign for example a name, if you want to do that you would have to create a new object with the same properties but with the new name. Immutable = Not Mutable

Why bother?

I didn't understand the point of immutable objects, I though that as long as we encapsulate and follow good object oriented guidelines then we are good to go.. Right?
Let's look at a naive example of things that can go wrong:
public class CSharpPoco
{
    private uint _value;
    public uint Value => _value;
    public void Increment()
    {
        _value++;
    }
    public uint GetNext()
    {
        Increment();
        return _value;
    }
}
        
public class ServiceLayer
{
    private CSharpPoco _poco = new CSharpPoco();
    public CSharpPoco GetPoco()
    {
        return _poco;
    }
    public uint PreviewNextValue()
    {
        return _poco.GetNext();
    }
}

In the service layer we have 2 methods to call, get the poco and preview its next value.
The following service code would throw the side effect exception:

var service = new ServiceLayer();
var poco = service.GetPoco();
var firstValue = poco.Value;
var preview = service.GetPreviewValue();
if (preview <= firstValue)
    throw new Exception("preview can't be smaller then or equal to the previus value");
if (poco.Value == preview)
    throw new Exception("side effect");

Meaning, we get an unexpected side-effect by calling the second method in the service. It manages to change the value of the first service calls result. It was zero, but after the preview call it has been set to 1. This is quite a simple example, but after having debugged scenarios like these in production code with huge code bases.. You get the idea, a unexpected side effect is often a cause for hard-to-find bugs.
So, how could immutability have helped us here? once the var poco = service.GetPoco() was called, the result would never change. Preferably we would not be able to reasign the variable poco to other references either (similar to the const keyword in TypeScript or F# let). So instead of var I would have liked a const poco = service.

What options do we have in .NET?

Readonly objects in C# with constructor lists

public class CSharpImmutableConstructorList
{
    public readonly Guid Id;
    public readonly string Name;
    public readonly string DisplayName;
    public CSharpImmutableConstructorList(Guid id, string name, string displayName)
    {
        Id = id;
        Name = name;
        DisplayName = displayName;
    }

    public CSharpImmutableConstructorList SetDisplayName(string displayName)
    {
        return new CSharpImmutableConstructorList(Id, Name, displayName);
    }
}
Basically the magic here is done by the readonly keyword that states that only the constructor can set the value of the variable. Once it has been set, it can only be read. For larger objects, it can get a little heavy on the constructor and you have to supply all the values every time you want to change. For example the SetDisplayName function, it supplies the Id and Name even though they have the same value as before.
If we add more properties to this class, we would have to change all calls to the constructor and add the new properties for them as well. So a little heavy on the maintenance side.

Readonly objets in C# with Modify pattern

public class CSharpImmutableModifyPattern
{
    public readonly Guid Id;
    public readonly string Name;
    public readonly string DisplayName;
    public static CSharpImmutableModifyPattern Default { get; } = new CSharpImmutableModifyPattern(Guid.Empty, string.Empty, string.Empty);
    private CSharpImmutableModifyPattern(Guid id, string name, string displayName)
    {
        Id = id;
        Name = name;
        DisplayName = displayName;
    }
    public CSharpImmutableModifyPattern Modify(Guid? id = null, string name = null, string displayName = null)
    {
        return new CSharpImmutableModifyPattern
            (
                id ?? Id,
                name ?? Name,
                displayName ?? DisplayName
            );
    }
    public CSharpImmutableModifyPattern SetDisplayName(string displayName)
    {
        return Modify(displayName: displayName);
    }
}
This is pretty much the same pattern as I've described in a previous post (Functional adventures in .NET C# - Part 1, immutable objects), the difference is that we use the readonly members instead of get-only fields.
Also note that the constructor is set to private to prevent usage of it from outside, instead we will use the Default static get-only field that sets up a default invariant of the class and call the new method Modify on it.
The nice thing with the Modify pattern is that you don't have to supply anything else then the changed property as shown in the SetDisplayName method. Even if we add new parameters, we don't have to change the SetDisplayName method as it specifies that it only wants to supply the displayName and nothing else.

Record types in F#

module Techdump =
    open System
    type FSharpRecord =
        {
            Id : Guid
            Name : string
            DisplayName : string
        }
        member this.SetDisplayName displayName =
            { this with DisplayName = displayName }

The F# Record version of the same type as show before. Used from C# this type feels similar to the C# Constructor List version as you have to supply all the constructor parameters when calling new. The magic happens in the SetDisplayName function that takes a new displayName value and then calls the record constructor with the current record and whatever fields have changed. I.e. the with keyword in record construction. We get the power of CSharpImmutableModifyPattern, but without having to maintain a Modify method, it is all included in the language.


Performance

In this part we will look at the run-time performance the different immutable patterns described above. 

Performance test source code


CSharpPoco
public class CSharpPoco
{
    public Guid Id { get; private set; }
    public string Name { get; private set; }
    public string DisplayName { get; private set; }
    public CSharpPoco(Guid id, string name, string displayName)
    {
        Id = id;
        Name = name;
        DisplayName = displayName;
    }

    public void SetDisplayName(string displayName)
    {
        DisplayName = displayName;
    }
}
Added a C# poco object so that we have a baseline to run against. I.e, here we just mutate the object. No new instance is created, this is the traditional way of changing a value in an object.

Performance tester
public class ImmutabilityPerformance
{
 public void Execute()
 {
  Log("--------------------------------------");
  Log("... ImmutabilityPerformance");
  ExecuteTest(1_000_000);
 }
 
 
 private void ExecuteTest(int iterations)
 {
  string s = string.Empty;
  try
  {
   var data = new List<string> { "Melissa Lewis", "Maya", "Smith", "Beverly Marsh", "Jane Vasko", "Molly Bloom" };
   var csharpPocoTimings = new RunningAverage();
   var fsharpRecordTimings = new RunningAverage();
   var csharpConstructorTimings = new RunningAverage();
   var csharpModifyTimings = new RunningAverage();
   for (int i = 0; i < iterations; i++)
   {
    var csharpPoco = new CSharpPoco(Guid.NewGuid(), "Jessica Chastain", "Jessica Chastain");
    var fsharpRecordOriginal = new Techdump.FSharpRecord(Guid.NewGuid(), "Jessica Chastain", "Jessica Chastain");
    var csharpConstructorOriginal = new CSharpImmutableConstructorList(Guid.NewGuid(), "Jessica Chastain", "Jessica Chastain");
    var csharpModifyOriginal = CSharpImmutableModifyPattern.Default.Modify(Guid.NewGuid(), "Jessica Chastain", "Jessica Chastain");

    for (int dataIndex = 0; dataIndex < data.Count; dataIndex++)
    {
     var item = data[dataIndex];


     csharpPocoTimings.Add(TimeAction(() =>
     {
      csharpPoco.SetDisplayName(item);
     }));
     if (csharpPoco != null)
      s = csharpPoco.DisplayName;

     Techdump.FSharpRecord fsharpRecordModified = null;
     fsharpRecordTimings.Add(TimeAction(() =>
     {
      fsharpRecordModified = fsharpRecordOriginal.SetDisplayName(item);
     }));
     if (fsharpRecordModified != null)
      s = fsharpRecordModified.DisplayName;

     CSharpImmutableConstructorList csharpConstructorModified = null;
     csharpConstructorTimings.Add(TimeAction(() =>
     {
      csharpConstructorModified = csharpConstructorOriginal.SetDisplayName(item);
     }));
     if (fsharpRecordModified != null)
      s = csharpConstructorModified.DisplayName;

     CSharpImmutableModifyPattern csharpModifyModified = null;
     csharpModifyTimings.Add(TimeAction(() =>
     {
      csharpModifyModified = csharpModifyOriginal.SetDisplayName(item);
     }));
     if (csharpModifyModified != null)
      s = csharpModifyModified.DisplayName;
    }
   }
   Log($"CSharpPoco\tIterations:\t{iterations}\tAverage:\t{csharpPocoTimings.Average:0.000}\tticks\tTotal:\t{csharpPocoTimings.Total:0.000}\tticks");
   Log($"FSharpRecord\tIterations:\t{iterations}\tAverage:\t{fsharpRecordTimings.Average:0.000}\tticks\tTotal:\t{fsharpRecordTimings.Total:0.000}\tticks");
   Log($"CSharpImmutableConstructorList\tIterations:\t{iterations}\tAverage:\t{csharpConstructorTimings.Average:0.000}\tticks\tTotal:\t{csharpConstructorTimings.Total:0.000}\tticks");
   Log($"CSharpImmutableModifyPattern\tIterations:\t{iterations}\tAverage:\t{csharpModifyTimings.Average:0.000}\tticks\tTotal:\t{csharpModifyTimings.Total:0.000}\tticks");
  }
  catch (Exception ex)
  {
   Log($"Fail\tDataCount\t2\tIterations:\t{iterations}\tFailed\t{ex.Message}");
  }
 }


 private float TimeAction(Action action)
 {
  var sw = Stopwatch.StartNew();
  action();
  sw.Stop();
  return sw.ElapsedTicks;
 }

 private void Log(string s)
 {
  Console.WriteLine(s);
  File.AppendAllText(@"c:\temp\enumToStringTest.txt", $"{s}{Environment.NewLine}");
 }
 
}

And the RunningAverage class from a previous post.

Results

ImmutabilityPerformance
Iterations
Average (ticks)
Total (ticks)
CSharpPoco 1000000 0.090 537402
FSharpRecord 1000000 0.121727156
CSharpImmutableConstructorList 1000000 0.120 720220
CSharpImmutableModifyPattern 1000000 0.161 965545

Here we can see that the poco baseline test is the fastest by far. Using the F# Record type and C# locked down object with constructor are pretty much equal in execution. The modify pattern in the C# code really drops the performance but gives more readable code, at least if we have long constructor lists in objects.

Rewritten increment example

Let's go back and look at the first increment example again and try to rewrite it with immutability
public class CSharpImmutable
{
    public readonly uint Value;
    public CSharpImmutable(uint value)
    {
        Value = value;
    }
    public CSharpImmutable Increment()
    {
        return new CSharpImmutable(Value + 1);
    }
    public uint GetNext()
    {
        return Value + 1;
    }
}

And in F#
type FsharpIncrement =
    {
        Value : uint32    
    }
    member this.Increment () =
        { this with Value = this.Value + 1u }
    member this.GetNext () =
        this.Value + 1u

Conclusions

In my opinion Immutable objects are the way to go if you want to write maintainable code for the long run, what technique you choose is entirely up to you. There are probably other ways to achieve the same that I don't know about, if you have ideas please post a comment!

After I started writing F# code, and started getting all the immutability features for free and especially the with keyword for records has persuaded me to start writing all my core business models in F#.
let point' = { point with X = 2; }
In my eyes, that line of code just there, is so damn beautiful.



All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Use for whatever you want, how you want! If you find this helpful, please leave a comment or share a link, not required but appreciated! :)

Friday, September 28, 2018

FSharp Enum ToString vs. C# Enum Dictionary Lookup for Localization


I was reading Tao Liu's post regarding enums with space for localization to save time and I just had to run a test if this really was faster then defining a lookup table?


On my computer
--------------------------------------
... FsharpEnumToString vs. CSharpEnumDictionaryLookup
FSharpToString  Iterations: 10000000;  Average: 0,287 ticks; Total: 14374450,000 ticks;
CSharpLookup    Iterations: 10000000;  Average: 0,134 ticks; Total: 6688315,000 ticks;

So, a simple dictionary lookup is still faster then ToString of a F# enum.
So I'll guess my team will keep the localization as data files / database table that is loaded at runtime into a variable. This way we can outsource the translations to other teams and specialists while keeping the code clean. A misspelled enum member by a tired developer does not result in a hotfix of an application with new builds etc, just a data file update in runtime.


The code used to perform this test:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using fsharp.techdump;

namespace techdump.console.Tests
{
    public class FsharpEnumToStringVsLookup
    {
        private Dictionary<CSharpEnum, string> _lookup = new Dictionary<CSharpEnum, string>
        {
            { CSharpEnum.Registration, "Registration" },
            { CSharpEnum.UnderReview, "Under Review" },
            { CSharpEnum.Approval, "Approval" },
            { CSharpEnum.Release, "Release" },
            { CSharpEnum.PostRelase, "Post Release" }
        };
        private enum CSharpEnum
        {
            Registration = 0,
            UnderReview = 1,
            Approval = 2,
            Release = 3,
            PostRelase = 4,
        }
        public void Execute()
        {
            Log("--------------------------------------");
            Log("... FsharpEnumToString vs. CSharpEnumDictionaryLookup");
            ExecuteTest(10_000_000);
        }
        
        
        private void ExecuteTest(int iterations)
        {
            string s = string.Empty;
            try
            {
                var index = new List<int> { 0, 1, 2, 3, 4 };
                var fsharpToStringTimings = new RunningAverage();
                var csharpLookupTimings = new RunningAverage();
                for (int i = 0; i < iterations; i++)
                {
                    for (int dataIndex = 0; dataIndex < index.Count; dataIndex++)
                    {
                        var item = index[dataIndex];
                        var fsharpEnumMember = (Techdump.FsharpEnum)item;
                        fsharpToStringTimings.Add(TimeAction(() =>
                        {
                            s = item.ToString();
                        }));
                        if (!string.IsNullOrEmpty(s))
                            s = string.Empty;
                        var csharpEnumMember = (CSharpEnum)item;
                        csharpLookupTimings.Add(TimeAction(() =>
                        {
                            s = _lookup[csharpEnumMember];
                        }));
                        if (!string.IsNullOrEmpty(s))
                            s = string.Empty;
                    }
                }
                Log($"FSharpToString\tIterations:\t{iterations}\tAverage:\t{fsharpToStringTimings.Average:0.000}\tticks\tTotal:\t{fsharpToStringTimings.Total:0.000}\tticks");
                Log($"CSharpLookup\tIterations:\t{iterations}\tAverage:\t{csharpLookupTimings.Average:0.000}\tticks\tTotal:\t{csharpLookupTimings.Total:0.000}\tticks");
            }
            catch (Exception ex)
            {
                Log($"Fail\tDataCount\t2\tIterations:\t{iterations}\tFailed\t{ex.Message}");
            }
        }


        private float TimeAction(Action action)
        {
            var sw = Stopwatch.StartNew();
            action();
            sw.Stop();
            return sw.ElapsedTicks;
        }

        private void Log(string s)
        {
            Console.WriteLine(s);
            File.AppendAllText(@"c:\temp\enumToStringTest.txt", $"{s}{Environment.NewLine}");
        }
        
    }
    
}

FSharp Enum defined as follows:
namespace fsharp.techdump

module Techdump =
    type public FsharpEnum =
        Registration = 0
        | ``Under Review``=1
        | Approval = 2
        | Release = 3
        | ``Post Release`` = 4


And the RunningAverage class from a previous post.


Wednesday, September 26, 2018

GeoCoordinateWatcher and GMap.NET

Playing around a little with the GMap.NET - Maps For Windows and figured I would use my computers location as a startup point for the map view.
Ended up encapsulating System.Device.Location.GeoCoordinateWatcher in a static class to get around the NaN coordinates returned from an uninitialized GeoCoordinateWatcher as it turns out that GMap.NET doesn't like NaN at all.
using System.Device.Location;

namespace dreamstatecoding.blogspot.com
{
    public static class GeoProvider
    {
        private static GeoCoordinateWatcher _watcher = new GeoCoordinateWatcher();
        public static bool IsInitialized { get; private set; }

        static GeoProvider()
        {
            _watcher.PositionChanged += _watcher_PositionChanged;
            _watcher.Start();
        }
        public static void Cleanup()
        {
            _watcher.Stop();
            _watcher.Dispose();
            _watcher = null;
        }
        private static void _watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            IsInitialized = true; ;
        }

        public static GeoCoordinate GetCoordinates()
        {
            var coordinates = _watcher.Position.Location;
            if (double.IsNaN(coordinates.Latitude))
                return new GeoCoordinate(0, 0);
            return coordinates;
        }
    }
}

Usage: Giving the provider some time to get hold of the first coordinates. If it doesn't, the coordinate returned would be longitude:0;latitude:0. So pretty much in the ocean outside of Africa.
private void SetupMap()
{  
 for(int i = 0; i < 1000; i++)
 {
  if (GeoProvider.IsInitialized)
   break;
  Thread.Sleep(151);
 }
 var coordinates = GeoProvider.GetCoordinates();
 gmap.MapProvider = GMapProviders.GoogleMap;
 gmap.Position = new PointLatLng(coordinates.Latitude, coordinates.Longitude);
 gmap.MinZoom = 0;
 gmap.MaxZoom = 24;
 gmap.Zoom = 15;
}

It seems that the thread in the GeoCoordinateWatcher is not set to Background as default. So I just force kill it when the application shuts down for now. I put this in my Program.cs file in the WinForms project:
[STAThread]
static void Main()
{
 Application.ApplicationExit += Application_ApplicationExit;
 
 Application.EnableVisualStyles();
 Application.SetCompatibleTextRenderingDefault(false);
 Application.Run(new Form1());
}        
private static void Application_ApplicationExit(object sender, EventArgs e)
{
 GeoProvider.Cleanup();
}


All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Use for whatever you want, how you want! If you find this helpful, please leave a comment or share a link, not required but appreciated! :)

The elegance of a F# WebRequest


Love the elegance of doing a WebRequest in F#

module WebLoader =
    open System.Net
    open System.IO

    let GetString (url:string) =
        let request = WebRequest.Create(url)
        use response = request.GetResponse()
        use stream = response.GetResponseStream()
        use reader = new StreamReader(stream)
        reader.ReadToEnd()

Especially the use keyword compared to the C# using { } blocks. Me like!