C# 7 Additions – Deconstructors

C# has a new type of method, the Deconstructor. When a type implements this method type with the name of Deconstruct, multiple variables maybe directly assigned as a return type would.

The method must be named Deconstruct and have a return type of void. The parameters to be assigned all must be out parameters, and because they are out parameters with a return type of void, C# allows the Deconstruct method to be overloaded solely based on these parameters. This is how the new System.ValueTuple allows it’s properties to be assigned to separate variables without assigning each one individually.

Deconstruct also does not need to be directly attached to the class. C# allows the method to be implemented as an extension method as well.

At the moment it is uncertain if wildcards will be added allowing unneeded variables to be omitted from being assigned. This addition would allow the insertion of the * to indicate a parameter is not needed (similar to _ in F#)

C# 7 Additions – Tuples

In C# 7 Microsoft has introduced an updated Tuple type. It has a streamlined syntax compared to it’s predecessor making it fall it look more like F#. Instead of declaring it like previous versions, the new Tuple type looks like:

Likewise to declare it as a return type, the syntax is similar to declaring it:

The first thing to note about the new type is that it is not included automatically in a new project. If you immediately use it, you’ll see the following error.

As of VS 15 preview 4 (not to be confused with VS 2015), you must include the System.ValueTuple Nuget package to take advantage of it.

This raises the question about how the new Tuple type and the previous one included since .NET 4 are related? They’re not. They are treated as two different types and are not compatible with each other.  System.Tuple is a reference type and System. ValueTuple is a value type.

So what are advantages over the previous version? The syntax simpler, and there are several other advantages.

Named Properties

In the System.Tuple version, properties of the return object were referenced as Item1, Item2 etc. This gets confusing when there are multiples of the same type in the Tuple as you have to know what position had which value type.

Now it’s possible to explicitly name the item types to reduce confusion.

The Item properties (Item1, Item2, etc.) have also been included allowing methods to be updated to the new type without breaking code based on it’s predecessor.

It’s also possible to explicitly name the values when creating the object:

Deconstruction

It is now possible to name and assign variable values upon creating (or returning) a tuple. Although not necessary, it reduces the amount of code necessary to pull values out of the type.

It’s not certain if C# will get wildcards like F# to automatically discard values which aren’t needed. If they are allowed then it’s possible to only create a variable for the name like so:

Updating Values

System.Tuple is immutable.  Once created it’s not possible to update any of the values.  This restriction has been removed in the new version.  From a purely functional perspective this could be considered a step backwards, but in C# many people find this approach more forgiving and beneficial.

Like all value types, when it is passed into a method, a copy of the tuple is created, so modifying it in the in the method does not affect the original.

However if you compare two different tuples and they have the same values, the Equals method compares the values in each and if they are all equal, it considers them equal.

Integrations with Other Languages

Unfortunately, C#’s new tuple type doesn’t automatically allow it to translate tuples from F#.

F# can’t desconstruct the values like it can with it’s native tuples, and to return it, you have to explicitly instantiate the object type and add the values.

Either way, the translation to F# isn’t horrible as it acts like any other object passed to it by C#.

Return From The Void

In a recent project, we were tasked with making a service layer more manageable and efficient, and with a tight deadline each minute needed to count. My teammate and I quickly moved methods around, created new classes where necessary, and implemented the Dapper object mapper. About half way into the final testing, my coworker looked at me and said, “The end date for a workflow isn’t updating. Do you think it’s a caching problem?” After looking through the code, I quickly found the issue. The SQL update procedure inside the update function wasn’t called. Fortunately, it was a simple fix, but it occurred to me we used this pattern dozens of times in the service tier. How many other places was this exact problem occurring that we haven’t found?

Testing caught the errors, but, the time spent tracking down this type of issue should have been avoided. I designed the update functions to return void instead of boolean or integer and relied on the implicit success of a method which solely performs a side effect (which functions that return void are) to indicate it executed correctly. I forgot when a method doesn’t throw an exception, it doesn’t mean the intended action was successful but only that it didn’t explicitly fail.

Take for example, the following two functions:

and

To the calling function, there is no difference. They both take the same parameter and return the same type (or not at all in this case), but to the overall system, there is a huge difference. One correctly updates the value, and the other doesn’t do anything and indicates nothing is wrong.

Applying the functional principal of always having an output from a function easily helps this issue:

and

Now the application won’t compile until the function is written to perform an action. The compiler helps enforce correct code.

In truth, there are ways to get around the compiler error and still have a non-functioning program. This is a common pattern seen over and over:

Comment out the change to numberOfRecordsUpdated, and the compiler states the code is valid. By applying another functional pattern, this problem code is also precluded. Enforcing the rule that variables should be immutable, removes this problem pattern since numberOfRecordsUpdated couldn’t be changed once it’s instantiated which means that it can’t have a default initialization of zero.