Evil Code #13 : Tuple Deconstruction Assignment

It is not often that I end up writing two back to back posts on Evil Code series, and that too on the same topic. But like I said in the previous post, Tuples are really an interesting topic (if you are reading Jon Skeet’s book, then everything is interesting)

In this post, we will explore a certain behavior of tuples observed during deconstruction assignment

Consider the following code.

var person = new Person{Name="Jia",Age=4};
var personCopy = person;
(person,person.Age) = (new Person{Name="Naina"},0.2);

Console.WriteLine($"Student => Name: {person.Name}, Age: {person.Age}");
Console.WriteLine($"StudentCopy => Name: {personCopy.Name}, Age: {personCopy.Age}");

The output might surprse you at the first glance, but seems reasonable as you attempt to understand what goes behind the deconstruction assignment. Let us look at the output first before we see what happens during the deconstruction.

Student => Name: Naina, Age: 0
StudentCopy => Name: Jia, Age: 0.2

This behavior attributes itself to the 3 stage process involved in the deconstruction assignment.

Note that unlike User defined type deconstruction, which requires invocation of Deconstruct method with appropriate number of parameters.

As Microsoft has put down in the feature description,

The evaluation order can be summarized as: (1) all the side-effects on the left-hand-side, (2) all the Deconstruct invocations (if not tuple), (3) conversions (if needed), and (4) assignments.

From the above, (2 & 3) aren’t part of our concern (it is a tuple and no conversion if required as the source/destination types are the same). In the first step, the side-effect of LHS is evaluated while only in the last step the actual assignments happen.

So in this case, each of the expresion on the Left hand side, is evaluated one by one, and a storage location is reserved for it.After this, the RHS is evaluated, and any conversion to destination type is done if required.

Finally the conversion results or values from the RHS is assigned to the storage location identified in the first step.

This would mean the above code gets roughly translated to

Person person = new Person
{
    Name = "Jia",
    Age = 4.0
};
Person personCopy = person;
// LHS is evaluated and storage for person.age is reserved
Person person2 = person;
//RHS is evaluated and converted if required
Person obj = new Person
{
    Name = "Naina"
};
double num = 0.2;

// assignments
person = obj;
person2.Age = num;

Notice that during the evaluation of LHS, space reservation and evaluation is done only for person.age and not for  person from (person,person.age). This is because when assigning to a property of a variable, an extra step is required to evaluate the value of variable. This step could be skipped when the target is a variable and not property of a variable.

That explains the output we received for the earlier code.

Note: If you are a C# developer, and haven’t read Jon Skeet’s C# in Depth, do it immediately. This book is a MUST read for any C# developer.

Evil Code #12: Tuple Parameter – Overloads and Overrides

Tuples is an interesting subject to go back to due to certain peculiar qualities it possess. In this section, we would address some of them.

To begin with, however, we will address how to tuples behave during method overloads – a pattern it share with rest of .Net. Consider the following code.

public class Foo
{
	public void Bar((int,object) param)
	{
	}
	
	public void Bar((int,dynamic) param)
	{
	}
}

Would the above code compile ? If not, why ?

Well, it doesn’t compile – of course. The compiler would complain that

Type 'Foo' already defines a member called 'Bar' with the same parameter types

This is because there is an identity conversion between object and dynamic, which results in compiler detecting both methods as signature with same parameter types. This is similiar to how it would have been if you had defined an overload as following.

public void Bar(object param)
{
}

public void Bar(dynamic param)
{
}

As one would guess, that isn’t allowed either.

The second scenario we would be checking is with regard to inheritance or interface implementations. Consider the following code.

public interface IBar
{
	void Foo((object left,object right) param);
}

public class Bar:IBar
{
	public void Foo((object left, dynamic right) param)
	{
	}
}

Now considering the identity conversion between object and dynamic, it is easy to guess that this would be allowed. However, the nasty part shows when you vary the name of the tuple variable. Consider the following code, where i have renamed the right parameter in tuple as center.

public interface IBar
{
	void Foo((object left,object right) param);
}

public class Bar:IBar
{
	public void Foo((object left, object center) param)
	{
	}
}

Notice, I have retained the types of each element and arity of the tuple. The only thing that has changed is the name of one of the elements in the tuple. This breaks the code with following exception.

The tuple element names in the signature of method 'Bar.Foo((object left, object center))' must match the tuple element names of interface method 'IBar.Foo((object left, object right))' (including on the return type).

Isn’t that interesting ? I would rather use the word scary. Imagine as a library developer you rename of the tuple parameters in your API and it breaks all the clients.

This would be one change I wish the elite team working .Net manages to fix as this is quite unlike rest of the .Net.

Evil Code #011 : Tuples

It has been long since I wrote a post in Evil Code series. So here is a short one, using the Tuples which was introduced in C# 7.X.

“introduced in C# 7.x” . You must be wondering why I used that phrase. Tuples was there before 7.x right ? Well, the answer is both yes and no. Tuples did exist before 7.x, but the one introduced in 7.x isn’t exactly the same. This newer version is a struct called System.ValueTuple and are noticeably different from its predecesoor in following ways.

  • System.ValueTuple is a struct, while System.Tuple is a reference type.
  • System.ValueTuple is mutable, while System.Tuple is not.
  • System.ValueTuple exposes items via Fields, while System.Tuple exposes items via properties.

You might have already seen a thousand articles on Tuples and have used them in your code base. So I would not go into further details on semantics and usages, but we will explore a special case.

Consider the following code.

var tuple1 = (Item1:1,Item2:2);
var tuple2 = (1,2);
var tuple3 = (Item2:2,Item1:1);

What would be the output of above code ?

Well, it would not even compile. The last would throw an error.

CS8125 Tuple element name 'Item2' is only allowed at position 2.
CS8125 Tuple element name 'Item1' is only allowed at position 1.

Why is it so ? Tuples can be broadly categorized in two ways – tuple literal and tuple types.

Tuple literals has a value and an optional name, while tuple typeshave type and optional name. In both cases, the name is optional and could be anything, except when the naming pattern uses the ItemN syntax.

These are reserved names which the tuple reserves for unnamed Tuple. You could use them as well, however, you are not allowed to alter the order.

Every element in the tuple could be accessed by the name if present, or its position. For acessing the Tuple element with position, .Net uses the naming convension ItemN where N is the position in the Tuple (1 based index).

The first element in the Tuple has to be Item1, the second Item2 and so on. If you alter the naming convention and use Item2 as the first element, the compiler would complain as shown above.

If you are attempting to name the first element as Item2, you are basically creating an ambiguity (should use the word confusion). This is why the naming convension prohibits such a pattern.

That was a rather a simple one right ? But that is the thing I like about the Evil Code series. Most of them are quite simple, but somewhere in the details, there are hidden facts which one as a developer needs to be aware of.

A second look at char.IsSymbol()

Let us begin by examining a rather simple looking code.

var input = "abc#ef";
var result = input.Any(char.IsSymbol);

What would the output of the above code ? Let’s hit F5 and check it.

False

Surprised ?? One should not feel guilty if he is surprised. It is rather surprising one does not look behind to understand what exactly char.IsSymbol does. After all, it is one of the rather underused method.

So why this pecular behaior ? What exactly is a Symbol according to the char.IsSymbol() method. The answer lies in the documentation of the method.

Valid symbols are members of the following categories in UnicodeCategory: >MathSymbol, CurrencySymbol, ModifierSymbol, and OtherSymbol.

The character ‘#’ naturally doesn’t fall under the required categories. Now, with that understanding, let us examine few other characters.

var charList = new[]{'!','@','$','*','+','%','-'};
foreach(var ch in charList)
{
Console.WriteLine($"{ch} = IsSymbol:{char.IsSymbol(ch)}");
}

The output again, has few curious facts to verify. Let’s check the output first.

! = IsSymbol:False
@ = IsSymbol:False
$ = IsSymbol:True
* = IsSymbol:False
+ = IsSymbol:True
% = IsSymbol:False
- = IsSymbol:False

Some of the results are self-explanatory, but what looks interesting for us would be the characters "*","-", and "%". All three of them looks to fall under Mathematical symbols. This might raise eyebrows on why they weren’t recognized as Symbols.

The answer lies in the UnicodeCategory of the character. Let us change the code a bit to include the unicode category as well for each character.

var charList = new[]{'!','@','$','*','+','%','-'};
foreach(var ch in charList)
{
Console.WriteLine($"{ch} = IsSymbol:{char.IsSymbol(ch)}"
+ $"UnicodeCategory:{Char.GetUnicodeCategory(ch)}");
}

Before further discussion let us examine the output as well.

! = IsSymbol:FalseUnicodeCategory:OtherPunctuation
@ = IsSymbol:FalseUnicodeCategory:OtherPunctuation
$ = IsSymbol:TrueUnicodeCategory:CurrencySymbol
* = IsSymbol:FalseUnicodeCategory:OtherPunctuation
+ = IsSymbol:TrueUnicodeCategory:MathSymbol
% = IsSymbol:FalseUnicodeCategory:OtherPunctuation
- = IsSymbol:FalseUnicodeCategory:DashPunctuation

The answer to previous question now stares on us. The characters "*,%,-" lies under the OtherPunctuation and DashPunctuation Categories.

That explains the behavior of char.IsSymbol(). In most cases, it would be better to use Regex for validating passwords or other strings that needs to be validated for special characters.

Evil Code #010 : Extension Methods

Back with Evil Code Series again. What would be the output of the following.

void Main()
{
PrintToString("SampleText");
PrintToDescription("SampleText");
PrintToString(null);
PrintToDescription(null);
}
public void PrintToString(string valueToPrint)
{
Console.WriteLine($"Printing From {nameof(PrintToString)} : {valueToPrint.ToString()}");
}

public void PrintToDescription(string valueToPrint)
{
Console.WriteLine($"Printing From {nameof(PrintToDescription)} : {valueToPrint.ToDescription()}");
}

public static class Extensions
{
public static string ToDescription(this string source)
{
return $"Description = {source??"Null"}";
}
}

The code attempts to prints 2 set of data, “SampleText” and Null Value. The PrintToString method, prints the output from the inbuild ToString() method, while the second method PrintToDescription, prints the output from an extension method.

The extension method, as such, doesn’t do anything fancy. It merely adds a prefix to the string (if not null or prints null).

It would be natural to expect the firs two method calls to print normally and then the last two calls, with null as paramter, to throw exceptions. But this is where things to change and expose the functioning of Extension methods.

While the extension methods work quite similiar to instance method, there is one fundamental difference. It has ability to execute even if the source instance if null.

In our given code, in the final call to PrintToDescription, even with a null paramter, the extension method is invoked, while the PrintToString would throw an exception as soon as null.ToString is encountered.

The output of the above code would be as following.

1. Printing From PrintToString : SampleText
2. Printing From PrintToDescription : Description = SampleText
3. // Throws Exception
4. Printing From PrintToDescription : Description = Null

Evil Code #009 : nameof Operator

The nameof() operator has been so commonly used by the developers that one could not be called guilty if he assumes it was there since C# was born. Despite that, there are days it might still surprise you.

What would be your reply if I asked you to predict the output of the following.

nameof(School.Division.Student)

No prizes for guessing. It wouldn’t be hard to guess that the output would be “Student”. So what is the surprise factor.

Let me add some more constraint to the code. What could be the output is the code was compiled on Visual Studio 2017, v15.5.x ? Would your answer change ?

If you were to say that you answer would still be the same, then here is the surprise for you. This is a bug on the C# compiler, which results in compiler error when you use nested properties /sub expression of the format X.Y.Z.

CS0120: An object reference is required for the non-static field, method, or property 'C.Instance'

This bug was fixed in 15.7.x, and anyone using a Visual Studio with version 15.7.x or above, would be able to see the desired result of “Student”.

If you are one of those lucky ones as yours truely, then you are in for an unusual compiler error. If you are interested to read more on the issue, please follow the issue on Github here.

Evil Code #008: Property Instance

It has been long since I blogged on Evil Code series. Time to check one again now. Consider two samples of code.

Sample 1

public class AnotherClass
{
public MyClass ClassInstance{get;set;}
}

public class TestClass1
{
public AnotherClass AnotherClass{get;set;}
public int Id
{
get=> AnotherClass.ClassInstance.Id;
set=> AnotherClass.ClassInstance.Id=value;
}
}

public class MyClass
{
public int Id{get;set;}
}

Sample 2

public class AnotherClass
{
public MyStruct StructInstance{get;set;}
}

public class TestClass2
{
public AnotherClass AnotherClass{get;set;}
public int Id
{
get=> AnotherClass.StructInstance.Id;
set=> AnotherClass.StructInstance.Id=value;
}
}
public struct MyStruct
{
public int Id{get;set;}
}

How differently would two of the code samples given below behave ?

Well, Sample 1 compiles and Sample 2 doesn’t. Why ?? Sample 2, in fact raises following error.

Cannot modify the return value of 'AnotherClass.StructInstance' because it is not a variable

Could you reason why ?

If you look into the two Sample codes, there is a significant difference. MyStruct, used by Sample 2 is a value type. This means that when you are are in fact accessing a copy of StructInstance and not the valeu itself ( as you would have had it been a class – reference type).
Any change made in the property is made on the Copy instance, and then disregarded, leaving the original value unchanged.

This is the reason compiler warns you against.

Evil Code #007: Overloads

Time to do a bit of Evil Code again. Let’s look into following set of classes first.

public class BaseParameter { }
public class DerievedParameter :BaseParameter { }

public class BaseClass
{
   public void Foo(DerievedParameter param) => Console.WriteLine($"Inside {nameof(BaseClass)}");
}

public class DerievedClass : BaseClass
{
   public void Foo(BaseParameter param) => Console.WriteLine($"Inside {nameof(DerievedClass)}");
}

The client code looks like following.

var instance = new DerievedClass();
instance.Foo(new DerievedParameter());
instance.Foo(new BaseParameter());

What could be output of the above ? There might be tendency that the one might be inclined to think about an output that resembles following.

Inside BaseClass
Inside DerievedClass

But interestingly that is not quite right. The overload rules ensures that when there is a probable method in the most derieved compile type, the derieved method is chosen, even if there is a better choice in base class. The output of the code would be as following.

Inside DerievedClass
Inside DerievedClass

This is one of the reasons why overloading of base class methods are not recommended.

Let’s take a step further and introduce IEnumerable as method parameters. That’s when things get even more interesting.


public class BaseClass
{
  public void Foo(DerievedParameter param) => Console.WriteLine($"Inside {nameof(BaseClass)}");
  public void Bar(IEnumerable<DerievedParameter> paramList) => Console.WriteLine($"Inside {nameof(BaseClass)}");
}

public class DerievedClass : BaseClass
{
  public void Foo(BaseParameter param) => Console.WriteLine($"Inside {nameof(DerievedClass)}");
  public void Bar(IEnumerable<BaseParameter> paramList) => Console.WriteLine($"Inside {nameof(DerievedClass)}");
}
 instance.Bar(new List<DerievedParameter> { new DerievedParameter(), new DerievedParameter() });
instance.Bar(new List<BaseParameter> { new BaseParameter(), new BaseParameter() });

What could be the output of above ? As per our earlier knowledge, the output would be

Inside DerievedClass
Inside DerievedClass

Well, the actual answer is slightly more complicated. If you are running the code in a framework above 4.0, then you are bang on target. But, if the target framework is lesser, you are in for a surprise.

Inside BaseClass
Inside DerievedClass

The reason for the above scenario is that post 4.0, C# generic interfaces support covariance and contravariance, which wasn’t the case for frameworks prior to that. This results in above scenario.

Happy Coding

Evil Code #006 : Build Configurations

This one is courtesy Wouter de Kort, from his famous book. Okay, so what’s the evil code here. Consider the following code and predict the output in Debug as well as Release modes.

static int count = 10;
static void Main(string[] args)
{
  Timer timer = new Timer(CallBackMethod, null, 0, 2000);
  Console.ReadLine();
}

private static void CallBackMethod(object state)
{
  if (--count == 0)
  Environment.Exit(0);

  Console.Write(count);
  GC.Collect();
}

Output of the code under different configurations

// Debug Mode
987654321
// Release Mode
9

Isn’t that weird that the output has varied in Debug and Release modes ? Well, the key player in charge of this different output is the Garbage Collector and code optimization. When in the Release mode, the compiler optimizes the code realizing that timer object is not used again. This results in the CallBackMethod being executed only once.

Evil Code #005 : Readonly Value Types

Time to review another of Evil Code Series and this time, we are dealing with read-only value types. Review the below code and predict the output.

 

struct DummyStruct
{
    public int MyValue {get; set;}
    public int Increment() => ++MyValue;
    public DummyStruct(int myValue)=> MyValue = myValue;
}
public class DemoClass
{
    private readonly DummyStruct _readOnlyStruct;
    public DemoClass() => _readOnlyStruct = new DummyStruct(2);
    public void IncrementAndDisplayValue() => Console.WriteLine($"({_readOnlyStruct.Increment()},{_readOnlyStruct.MyValue})");
}
var myClass = new DemoClass();
myClass.IncrementAndDisplayValue();

 

Strangely enough, the output is {3,2}. Yes, it means the Increment Method return a value of 3 for MyValue, but a follow-up statement to display MyValue explicitly, ends up with a value 2. Isn’t that bizarre ? Well not quite if one think a bit deeper.

Being a value type, whenever we are accessing it, we only get a copy of the value. The original _readOnlyStruct.MyValue is immutable and doesn’t change. But, the copy isn’t quite immutable and gets altered, which is returned by the Increment method. And when you are calling the _readOnlyStruct.MyValue property in the later part of program, another copy of the immutable value type is created which has the original value. This is the reason we are seeing the output. A more detailed explanation has been provided by Eric Lippert in his blog .
Happy Coding !!