Friday, 24 August 2018

Deconstruction Extensions and Multitargeting

In the last post I looked at Deconstructors in C# 7.0. I thought I'd create a library with a few extension methods to add Deconstructor support for Arrays and KeyValuePairs.

I started with adding extension methods for arrays. I developed the methods test-first and everything went pretty much as I expected it to. I ended up with methods supporting deconstruction of arrays from 2 elements up to 9. Here's the code for the 2-element method and its tests.

public static class ArrayDeconstructors
{
    public static void Deconstruct<t>(this T[] array, out T item1, out T item2)
    {
        EnsureNotNull(array, nameof(array));
        EnsureMinimumLength(array, 2, nameof(array));

        item1 = array[0];

        item2 = array[1];
    }
}

public class TwoElementDeconstructorShould : ArrayDeconstructionTest
{
    public TwoElementDeconstructorShould() 
        : base(elementCount: 2)
    {
    }

    protected override void TestDeconstruction<T>(T[] array)
    {
        var (first, second) = array;

        first.Should().Be(array[0]);
        second.Should().Be(array[1]);
    }
}

public abstract class ArrayDeconstructionTest
{
    public ArrayDeconstructionTest(int elementCount)
    {
        ElementCount = elementCount;
    }

    public int ElementCount { get; }

    protected string ExpectedUndersizeArrayMessage =>
        $"The provided array must have at least {ElementCount} elements." +
        Environment.NewLine + "Parameter Name: array";

    [Fact]
    public void ThrowArgumentNullExceptionGivenNullInput()
    {
        int[] array = null;

        Action deconstruction = () => TestDeconstruction(array);

        deconstruction.Should().Throw<ArgumentNullException>().WithMessage("*array");
    }

    [Fact]
    public void ThrowArgumentExceptionGivenEmptyInt32Array()
    {
        var array = new int[0];

        Action deconstruction = () => TestDeconstruction(array);

        deconstruction.Should().Throw<ArgumentException>()
            .WithMessage(ExpectedUndersizeArrayMessage);
    }

    [Fact]
    public void ThrowArgumentExceptionGivenInt32ArrayWithInsufficientElements()
    {
        var array = new int[ElementCount - 1];

        Action deconstruction = () => TestDeconstruction(array);

        deconstruction.Should().Throw<ArgumentException>()
            .WithMessage(ExpectedUndersizeArrayMessage);
    }

    [Fact]
    public void DeconstructInt32ArrayOfMinimumSizeAsExpected()
    {
        var array = Enumerable.Range(1, ElementCount).ToArray();

        TestDeconstruction(array);
    }

    [Fact]
    public void ReturnFirstElementsOfLargerArray()
    {
        var array = Enumerable.Range(1, ElementCount).Reverse().ToArray();

        TestDeconstruction(array);
    }

    [Fact]
    public void DeconstructStringArrayAsExpected()
    {
        var array = new[] { "foo", "bar", "baz", "qux", "quux", "quuz", "corge", "grault", "garply", "waldo" };

        TestDeconstruction(array);
    }

    protected abstract void TestDeconstruction<T>(T[] array);
}

Things did not go as expected when I started on support for KeyValuePair<K,V>. I'd created the project targeting .Net Standard 1.1, with a test project targeting .Net Core 2.1. I wrote the first test for a KeyValuePair<K,V>. Checking for null input is moot as KeyValuePair is a value type. So the first test I wrote was for an actual deconstruction. Here it is:

[Fact]
public void DeconstructKeyValuePairOfInt32Int32()
{
    var kvp = new KeyValuePair<int, int>(2, 4);

    var (key, value) = kvp;

    key.Should().Be(2);
    value.Should().Be(4);
}

Then I ran the test, expecting it to be red, actually expecting it to not even compile when the compiler couldn't find a Deconstruct method. Imagine my surprise when it not only compiled, but ran green! I had a passing test without writing a line of code.

Turns out that a Deconstruct method was added to KeyValuePair<K,V> in .Net Core 2.1. Here's what it looks like:

[EditorBrowsable(EditorBrowsableState.Never)]
public void Deconstruct(out TKey key, out TValue value)
{
    key = Key;
    value = Value;
}

The attribute decorating it hides the method from Intellisense, but the compiler knows it's there, and it just works.

So where to for my class library? I wanted the library to be able to be used in projects targeting any platform, so .Net Standard 1.1 was the right choice there. But a test project needs to target a concrete framework. I changed the test project to target .Net Core 2.0 and my test failed. That is, it failed to compile. I added a degenerate extension method so that the test would compile, but still not pass. Then I modified the test project to target multiple frameworks. In this case it was as simple as changing one line in the .csproj file from

<TargetFramework>netcoreapp2.1</TargetFramework>

to

<TargetFrameworks>netcoreapp2.1;netcoreapp1.1;net452;net47</TargetFrameworks>

I then ran dotnet test and it compiled and ran the tests for each of the targeted frameworks individually. The test passed for .Net Core 2.1, but failed for the others. Cool. So then I was able to finish the extension method, and get the class library to where I wanted it to be.

You can see the code on GitHub. Next step is to publish a NuGet package just on the off chance that someone might actually want to use it.

Friday, 22 June 2018

Fun with Deconstructors

In my last post I had some fun with C# initialisers. This time we'll look at Deconstructors that were introduced as part of the new ValueTuple support in C# 7.0. The code we'll look at this time will probably be slightly more useful for real-world propduction code.

The basics

I won't go into a great deal of detail on the basics here because it's already well covered in the above Microsoft docs link, and in another blog post about support for deconstructors in custom types. Suffice to say that ValueTuple types, and custom types with an appropriate Deconstruct() method can be deconstructed, or broken apart, to multiple variables in a single assignment statement. So you can do stuff like:
var point = (1.2, 5.3);
var (x, y) = point;

var customer = GetCustomer();
var (firstName, lastName) = customer;

Beyond the basics

Deconstructors are also supported for types you can't change by means of extension methods. So, we could deconstruct a DateTime, for example.
public static void Deconstruct(this DateTime value, out int year, out int month, out int day)
{
    year = value.Year;
    month = value.Month;
    day = value.Day;
}

var (year, month, day) = DateTime.Today;
Console.WriteLine($"Today is {year}/{month}/{day}");
That's cool, but you've probably read about that usage in a number of places. What I really want to look at, though, is what happens when you apply deconstruction to arrays.

Deconstructing arrays

You've probably seen, or written, code like this:
string[] nameComponents = customer.Name.Split(' ');
string firstName = nameComponents[0];
string lastName = nameComponents[1];

// Do something with firstName and lastName

In this code I deliberately left the types explicit, rather than using var, to make them clear.
If we define an appropriate extension method we can greatly simplify this code by removing a bunch of details that just get in the way of readibility.
public static void Deconstruct(this string[] array, out string value1, out string value2)
{
    value1 = array[0];
    value2 = array[1];
}

var (firstName, lastName) = customer.Name.Split(' ');
//Do something with firstName and lastName
Notice that the Deconstruct method only cares about the type of the array and the return (out) parameters. You can create multiple methods with different numbers of out parameters for arrays of different sizes. The method to use is chosen by the number of variables on the left side on your deconstruction assignment statement. Obviously you need to be careful that the array you're deconstructing actually has sufficient elements
You can see that this technique has immediate application to string parsing, but it could probably be useful for other scenarios as well, and also for arrays of other types. You don't need to define separate methods for different array types, however. This technique can also be used with generics:
public static void Deconstruct<T>(this T[] array, out T value1, out T value2)
{
    value1 = array[0];
    value2 = array[1];
}
Using this method you can now pull the first two elements out of an array of any type.
Pretty cool, huh? But we don't have to stop at arrays. Another area where assignments and ceremony get in the way is in iterating over dictionaries.

Deconstructing dictionaries

Okay, so we're not actually going to apply deconstruction to the dictionary itself, but deconstruction can be useful to improve readability when iterating over dictionaries. Before we get to that, though, let's look at how we typically enumerate a dictionary.

Let's say we're using a dictionary to keep a count of the occurrences of words in a block of text. We then want to report those results.
Dictionary<string, int> wordCounts = CountWords(text) ;
When we want to report these results we can enumerate the dictionary using a foreach loop.
foreach (var wordCount in wordCounts) 
{
    Console.WriteLine($"{wordCount.Key} : {wordCount.Value}");
}
This is fine. It works, and we can easily see what is doing. But the naming of things is not immediately clear, because it has more to do with the data structure we're using than the problem we're trying to solve. First, we have to have a name for each key-value pair in the dictionary. Secondly, the actual word and its count are accessed using the Key and Value properties, the names of which mean nothing in the business context. We could assign these values to all named local

We can improve this slightly by enumerating the keys in the dictionary, rather than the key-value pairs.
foreach (var word in wordCounts.Keys)
{
    Console.WriteLine($"{word} : {wordCounts[word]}");
} 
This is better, but there's still some ceremony in there. What happens if we define a deconstructor for the key-value pair? I'm glad you asked.
public static void Deconstruct<TKey, TValue>(this KeyValuePair<TKey, TValue> kvp, TKey key, TValue value) 
{
    key = kvp.Key;
    value = kvp.Value;
} 

foreach (var (word, count) in wordCounts)
{
    Console.WriteLine($"{word} : {count}");
} 
Look at that! A clear enumeration with well-named variables that clearly communicates the business concern with very little ceremony.

"But," you may say, "look at the variable names in the Decontruct method. They're meaningless." To which I would reply, "no they're not." That's a generic helper method that operates on any KeyValuePair, with names that are perfectly meaningful in that context. And really  what else are you going to call them?

But what about performance?

I could quote Donald Knuth about the evils of premature optimization, but I won't. Suffice to say, there's nothing to worry about.  I ran some tests timing 100 enumerations of a dictionary with 100k entries using each of the three techniques above. Each test run took 3-5 seconds to complete.

Enumerating the dictionary itself, as in the first example above, is the fastest option.  However, the third example, where we deconstruct the KeyValuePair, only has about a 1% performance hit.  Given the improvement in readability, I'd say that's worth it.

The worst option, performance wise, was the second example above where we enumerate the keys and then index into the dictionary in the loop. That had a 30-50% performance hit over enumerating the dictionary itself.

Conclusion

The new Deconstructor support in C#7.0 not only aids in handling ValueTuples, but can also be used to pull apart others types such as arrays and dictionaries with less code and greater readability.

Saturday, 16 June 2018

Fun with initialisers

C# has had object and collection initialisers since C# 3.0, but all the docs and blogs I’ve ever seen only cover the basics. We’ve all seen examples like these:
var address = new Address
{
    Line1 = "1 Microsoft Way",
    City = "Redmond",
    State = "WA",
    Zip = 98075
};

var languages = new List<string>
{
    "C#",
    "Java", 
    "Python"
};
But have you ever stopped to think what’s going on under the hood and considered the implications? I want to go there, but first let’s look at dictionaries.

Dictionary Initialisation

We’ve always been able to initialise a dictionary with a collection initialiser like this:
var months = new Dictionary<int, string>
{
    { 1, "January" },
    { 2, "February" },
    { 3, "March" },
    // and the rest, you get the idea
};
In C# 6.0 a new syntax was introduced, and in pretty much everything I’ve ever read about it it’s described as just that, a new way of writing the dictionary initialisations we’d all come to know and love, a different twist on Collection Initialisers. But the change in dictionary initialisation was actually a side-effect of adding indexer support to Object Initialisers. More on that later.

Collection Initialisers

Collection Initialisers work on any type that implements IEnumerable and has an Add(...) method (or, since C# 6.0, extension method). Look at the list of languages initialisation above. The compiler converts this to the equivalent of:
var _c = new List<string>();
_c.Add("C#");
_c.Add("Java");
_c.Add("Python");
var languages = _c;
The months dictionary initialisation works because of a similar transformation:
var _d = new Dictionary<int, string>();
_d.Add(1, "January");
_d.Add(2, "February");
// and the rest
var months = _d;
Note that this is basically then same as the list initialisation. The only difference is the number of parameters taken by the Add method. If you’re anything like me, your next thought is, “can this go beyond 2 parameters?”
Before I get to the answer, lets have another look at the requirements for collection initialisers. The two examples above use collection types that are included in the BCL, but that’s not a requirement. The only requirement is that the type implements IEnumerable, and that a suitable Add method is available. So, my next thought after the number of parameters was whether or not collection initialiser can handle multiple Add methods. The answer is pretty cool, but I’m not sure it’s useful for much in real world code.
It turns out that when the compiler is transforming the initialiser it looks for an appropriate Add method for each element of the initialiser. This means that you can actually have elements with differing numbers of items in one initialiser, as long as the Add methods are there to support them. Have a look at the following class:
class Foo1 : IEnumerable
{
    public void Add(long a) => Console.WriteLine("Add with one parameter");
    public void Add(string s1, string s2) => Console.WriteLine("Add with 2 strings");
    public void Add(bool f, double d) => Console.WriteLine("Add with 2 different params");
    public void Add(int x, char y, string z) => Console.WriteLine("Add with 3 parameters");


    // We need this to implement IEnumerable, but not for this example
    public IEnumerator GetEnumerator() => throw new NotImplementedException();
}
Note, that there’s nothing vaguely collection-like about this type, but it is a valid target for a collection initialiser. Here’s an example, and the output it produces:
new Foo1
{
    { "foo", "bar"},
    { 42 },
    { 3, '9', "27" },
    { true, 1.0 }
};
Output:
Add with 2 strings
Add with one parameter
Add with 3 parameters
Add with 2 different params
So now that we’ve abused collection initialisers, lets turn our attention elsewhere.

Object Initialisers

Before C# 6.0, object initialisers worked by setting fields or properties of the type being initialised. The compiler translates the Address initialisation at the top of this post into the equivalent of the following:
var _a  new Address();
_a.Line1 = "1 Microsoft Way";
_a.City = "Redmond";
_a.State = "WA";
_a.Zip = 98075;
var address = _a;
With C# 6.0 came support for setting indexers as well, and this is where the new dictionary initialisation syntax comes from. But initialising dictionaries is not the only place it can be used. Any type with indexers can use this style of initialisation, and it can be mixed with setting properties and fields. Consider this type:
class Foo2
{
    public string bar;
    public double Baz { set => Console.WriteLine("Property setter"); }
    public char this[int i] { set => Console.WriteLine("Indexer with 1 index"); }
    public string this[char c, int i] { set => Console.WriteLine("Indexer with 2 indices"); }
}
Here we have a field, a property, and two indexers with different number and types of indices. The following initialiser:
new Foo2
{
    bar = "bar1",
    [3] = '9',
    Baz = Math.PI,
    ['C', 4] = "Middle C"
};
produces this output:
Indexer with 1 index
Property setter
Indexer with 2 indices
Again, not sure how useful this is in real life or maintainable code, but it’s interesting nonetheless.

And back to Dictionaries

I’m going to wrap this post up with an interesting difference in behaviour when initialising dictionaries with the two different syntaxes available. Consider the following two initialisations:
var d1 = new Dictionary<int, string>
{
    { 1, "one" },
    { 1, "uno" }
};

var d2 = new Dictionary<int, string>
{
    [1] = "one",
    [1] = "uno"
}
On the face of it they look equivalent, but the behaviour is very different. The first attempts to call the Dictionary.Add method twice with the same key, resulting in an exception being thrown on the second call. The second initialiser just sets the dictionary indexer twice, resulting in a single entry with a key of 1 and a value of "uno".
I hope you've enjoyed my exploration (and abuse) of initialisers in C#. Till next time, “Happy Coding”.

Friday, 15 June 2018

Welcome to my new home

My first foray into blogging was 8 years ago, in 2010, when I was learning C# and .Net for the first time.  At the time I decided to blog about what I was learning as a way to help make things stick. Not only was I learning a new language and platform, but, as a result of my own personal "Hit Refresh" moment, I was learning a new discipline as I changed gears in my career from IT operations to software engineering.

That blog experience lasted for a year before I ran out of steam for a bit. I stopped blogging due to a mix of shifting personal priorities, a (un)healthy dose of imposter syndrome, and a progression in the complexity of the stuff I was learning. Part of it, too, was that I was getting opportunities at work to exercise and grow my software engineering skills on real projects, so my initial reason for blogging wasn’t such a need anymore.

Fast forward 2 years and I had somehow I managed to talk my way into a job at Microsoft, which meant relocating my family to Redmond. The five years since have been an amazing ride.  I’ve worked with some great people and learned a lot about my craft. We had a great experience living the USA for nearly 5 years and got to see a good chunk of the country.

At the start of this year we moved back to Australia for personal reasons, and I started working for WiseTech Global, a Sydney company developing software for the global logistics industry. I’ve been learning a bunch of platforms and frameworks that I hadn’t used before, and that got my blogging juices flowing again.

So, here I am, back in the saddle as it were, writing up stuff that’s on my mind, that I don’t want to forget, or that I think is cool and want to share with others.  I can’t promise it’ll be super entertaining or regular, but I’m back to give it ago.  Let’s see what happens…