Udemy

Story of Equality in .Net - Part 2

Sunday, June 26, 2016 0 Comments A+ a-

Introduction

In this post, we will see how smartly .Net handles equality and comparison out of the box. This means that you will be able to understand how .Net handles some of the issues that we discussed in the previous post.

If you remember from previous post,there are 4 methods in Object class which are provide by .Net framework for the purpose of equality checking but each one is designed for different scenarios but their purpose is same which is to check equality of two objects. In this post we will be focusing on the following three methods out of the four which are:
  1. virtual Object.Equals
  2. static Object.Equals
  3. static Object.ReferenceEquals

We will start by looking in detail at the virtual Object.Equals method. This provides the most important mechanism for equality checking in .Net, since it is the means by which any type can tell what equality means for itself. We will see how out of the box this method gives you reference equality for most reference types but value equality for all value types.
We will also compare it with the static method Object.Equals() which is of same name which is more robust when the scenario is that instances to be checked for equality can be null.

We will also see how we can guarantee that the equality check is done on the reference of instances not the values of the instances using the static Object.ReferenceEquals method.

After reading this post, I hope that you will have a good understanding what equality means in .Net.

Virtual Object.Equals() Method

As we discussed in the previous post as well, in .Net there are number of ways to compare equality, but the most fundamental way .Net provides for this purpose is the virtual Object.Equals() method defined in the System.Object type.

To see this method in action, we will create a class which represents a kind of person. The only thing our class contains is a string field containing the name of the person and a constructor that enforces to set the value of the name field.

    public class Person
    {
 
        private string _name;
 
        public string Name 
        { 
            get 
            { 
                return _name; 
            } 
        }
 
        public Person(string name)
        {
            _name = name;
        }
 
        public override string ToString()
        {
            return _name;
        }
 
    }

Now we will write the Main method to use this type.

    static void Main(String[] args)
    {
        Person p1 = new Person("Ehsan Sajjad");
        Person p2 = new Person("Ahsan Sajjad");
            
        Console.WriteLine(p1.Equals(p2));
    }  


As you can see in Main we are creating two instances of Person class passing different value as parameter to the constructor, and then on the next line we are checking for equality using the Object.Equals method. The equal method returns a Boolean, it returns true if both items are equals and false if they are not equal, we are writing the result of the equality comparison on the console to see what it outputs.
You would hope from the code that the two instances are not equal as “Ehsan Sajjad”  and “Ahsan Sajjad” are not equal they have different sequence of characters, and of course if we run the code we will see false as output on the console. So Equals() appears to be working right here and if you notice we didn’t have to do anything in our Person class definition to achieve this. The Equals method is provided by System.Object  so it is automatically available on all types, because all types ultimately derive from System.Object
By the way I suspect some of you may be looking at this code and thinking that the line p1.Equals(p2) is not what we write normally for checking equality, if we want to check for equality, we just write this p1 == p2, but the point here is we need to understand how equality works in .Net and the starting point for that is the Equals method.

== Operator and Equals Method

If you write == in your code, you are using the C# equality operator and that is a very nice syntactical convenience C# language provides to make the code more readable but it is not really part of the .Net Framework. .Net has no concept of operators, it works with methods. If you want to understand how equality works in .Net then we need to start with the things that .Net Framework understands. So we will only be using .Net methods in this post for most of the code, so you can see how it works , that means some of the code  you will see may look un-natural  but we will discuss  the == (c# equality operator) in another post.

Now let’s get back to the fun part i.e. code, we will declare another instance of Person in the Main program

This new instance p3 also passes same value in the constructor as p1 which is “Ehsan Sajjad”, so what do you think what will happen if we try to compare p1 with p3 using the Equals method, let’s try and see what happens:

    static void Main(String[] args)
    {
        Person p1 = new Person("Ehsan Sajjad");
        Person p2 = new Person("Ahsan Sajjad");
        Person p3 = new Person("Ehsan Sajjad");
            
        Console.WriteLine(p1.Equals(p3));
    } 


This also returns false, these two instances p1 and p3 are not equal and the reason is the base Object.Equals method evaluates reference equality, its implementation tests  whether two variables refers to the same instance, in this case it is obvious to us and that p1 and p3 have exactly the same value, both instances contains the same data but Equals method does not care about that, it care only about that they are same or different instances, so it returns false telling us that they are not equal.

As we discussed earlier in this post and in previous post as well that Equals is a virtual method in Object type which means that we can override it, if we want the Equals method to compare the values of the Person instances, we can override the Equals method  and can define our own implementation for how to compare two Person instances for equality, there is nothing unusual in this, Equals is a normal virtual method, we are not going to override it yet though, if you want to stick to good coding practices you need to do few other things when you override Object.Equals method, we will see later how to do that, for this post we will just stick to what Microsoft has given us  out of the box.

Equals Method Implementation for String

There are couple of reference types for which Microsoft has overridden the Object.Equals method in order to compare values instead of references, probably the well know of these and certainly the one that’s most important to be aware of is String, we will examine with a small program the demonstration of that:

    static void Main(String[] args)
    {
        string s1 = "Ehsan Sajjad";
        string s2 = string.Copy(s1);
            
        Console.WriteLine(s1.Equals((object)s2));
    }


In this program we initialize a string and store it’s reference in s1, then we create another variable s2 which contains the same value but we initializer s2 by creating a copy of the value s1 has, string.Copy method’s name is pretty descriptive, it creates and returns the copy of the string and then we are using Equals method to compare them.
You can see that we are casting argument of Equals method explicitly to object type that obviously you would not want to do in the production code, the reason we have done that here is to make sure that implementation of override of Object.Equals() is called, as string define multiple Equals method and one of them is strongly type to string i.e. it  takes string as parameter, if we didn’t cast it to object then the compiler would have considered the strongly typed method a better parameter when resolving overloads and would have called that one, that is obviously  better when we are normally programming and both method will actually do the same thing  but we explicitly wanted to show how the object.Equals override behaves, so we needed to cast parameter to object to tell the compiler to avoid strongly typed overload and use the object type override.

If we run the above code will see that it returns true. The override provided by Microsoft for string type compares the contents of the two string instances to check whether they contains exactly the same characters in the same sequence and returns true if they are otherwise returns false, even if they are not the same instance.

There are not many Microsoft defined reference types for which Microsoft has overridden Equals method to compare values, apart from String type, two others types that you must be aware of are Delegate and Tuple, calling Equals on these two will also compare the values, these are the exceptional ones all other reference types Equals will always do Reference equality check.

Equals Method and Value Types

Now we will see how Equals method works for value types, we will be using the same example that we used at start of the post (Person class ) but we will change it to struct instead of class for seeing the behavior in case of value type

    public struct Person
    {
 
        private string _name;
 
        public string Name 
        { 
            get 
            { 
                return _name; 
            } 
        }
 
        public Person(string name)
        {
            _name = name;
        }
 
        public override string ToString()
        {
            return _name;
        }
 
    }

What you think what will happen now if we run the same program again, as we know struct is stored on  the stack, they don’t have references normally unless we box them, that’s why they are called value type not reference type
    static void Main(String[] args)
    {
        Person p1 = new Person("Ehsan Sajjad");
        Person p2 = new Person("Ahsan Sajjad");
        Person p3 = new Person("Ehsan Sajjad");
            
        Console.WriteLine(p1.Equals(p2));
        Console.WriteLine(p1.Equals(p3));
    }

So as we know that the implementation of Object.Equals do the reference comparison in case of reference types but in this case you might think that comparing references does not makes sense as struct is a value type.

So let’s run the program and see what it prints on the console.


You can see that this time the result is different, for the second case it is saying that both instances are equal, it is exactly the result you would expect if you were to compare the values of both p1 and p3 instances of Person  to see if they were equal and that is actually happening in this case, but if we look at the Person type definition we have not added any code for overriding the Equals method of Object class, which means there is nothing written in this type to tell the framework that how to compare the values of instances of Person type to see if they are equal.


.Net already knows all that, it knows how to do that, .Net framework has figured out without any effort from us that how to tell p1 and p3 have equal values or not, how is that happening. What actually happening is that as you may already know that all struct types inherits from System.ValueType which ultimately derives from System.Object.
System.ValueType itself overrides the System.Object Equals method, and what the override does is that it traverses all the fields in the value type and call Equals against each one until it either finds any field value that is different or all fields are traversed, if all the fields turn out to be equal, then it figures out that these two value type instances are equal. In other words, value types override the Equals method implementation and says that both instances are equal if every field in them has same value which is quite sensible. In the above example our Person type has only one field in it which is the backing field for the Name property which is of type string and we already know that calling Equals on string compares values and the above results of our program proves what we are stating here. That’s how .Net provides the behavior of Equals method for value types very nicely.

Performance Overhead for Value Types

Unfortunately, this convenience provide by .Net framework comes with a price. The way System.ValueType Equals implementation works is by using Reflection. Of course it has to if we think about it. As System.ValueType is a base type and it does not know about how you will derive from it, so the only way to find out what fields in out defined type (in this case Person) has is to do it using Reflection which means that performance would be bad

Recommended Approach for Value Types

The recommend way is to override the Equals method for you own value types which we will see later how to provide that in a way that it runs faster, in fact you will see that Microsoft has done that for many of the built-in value types that comes with the framework which we use every day in our code.

Static Equals Method

There is one problem when checking for equality using the virtual Equals method. What will happen if one or both of the references you want to compare is null. Let’s see what happens when we call Equals method with null as argument. Let’s modify the existing example for that:

    static void Main(String[] args)
    {
        Person p1 = new Person("Ehsan Sajjad");
                        
        Console.WriteLine(p1.Equals(null));
    }

If we compile this and run, it returns false and it should and makes perfect sense because it is obvious that null is not equal to non-null instance and this is the principle of Equality in .Net that Null should never evaluate as equal to Non-Null value.

Now let’s make it vice versa to see what will happen if the p1 variable is null, then we have a problem. Consider that we don’t have this hardcoded instance creation code instead of that this variable is passed as parameter from some client code which uses this assembly and we don’t know if either of the value is null.
If p1 is passed as null, executing the Equals method call will throw a Null Reference Exception, because you cannot call instance methods against null instances.
The Static Equals method was designed to address this problem, so we can use this method if we are not aware if one of the objects could be null or not, we can use it this way:

    Console.WriteLine(object.Equals(p1,null));

Now we are good to go without worrying about if either of the instance reference is null, you can test it by running with both scenarios and you will see it works fine, and of course it would return false if one of the reference variable is null.

Some of you may be wondering that what would happened if both the arguments passed to Static Equals method are null, if you add the following line to test that:

    Console.WriteLine(object.Equals(null,null));

You will see that it returns true in this case, in .Net null is always equal to null, so testing whether null is equal to null  should always evaluate to true.

If we dig in to the implementation Static Equals method we will find that it is very simple implementation. Following is the logic of it if you look in to the source code of Object type:

public static bool Equals(object x, object y)
{
    if (x == y) // Reference equality only; overloaded operators are ignored
    {
        return true;
    }
    if (x == null || y == null) // Again, reference checks
    {
        return false;
    }
    return x.Equals(y); // Safe as we know x != null.
}


If first checks if both parameters refer to the same instance i.e. what == operator will do, this check will evaluate to true causing method to return true if both the parameters are null, the next if block will return false if one of the parameters is null and other one is not, finally if control reaches the else block then we know that both parameter point to some instance, so we will just call the virtual Equals method.
This means that the static Equals method will always give the same result as the virtual method  except that it checks for null first, as static method call the virtual method, if we override the virtual Equals method, our override will automatically be  picked by the static method, that’s important as we want both static virtual methods to behave consistently.

ReferenceEquals Method

ReferenceEquals serves a slightly different purpose from the two Equals method which we have discussed above. It exists for those situations where we specifically want to determine whether the two variables refer to the same instance. You may have question in mind that Equals method also checks reference equality then why a separate method.
Those two methods do check reference equality, but they are not guaranteed to do so, because the virtual Equals method can be overridden to compare values of the instance not the reference.
So, ReferenceEquals will give the same result as Equals for types that don’t have overridden the Equals method. For example, take the Person class example which we used above. But it’s possible to have different results for types that have overridden the Equals method. For Example, the String class.

Let’s modify the string class example that we used earlier in this post to demonstrate this:

    static void Main(String[] args)
    {
        string s1 = "Ehsan Sajjad";
        string s2 = string.Copy(s1);
            
        Console.WriteLine(s1.Equals((object)s2));
        Console.WriteLine(ReferenceEquals(s1,s2));
    }

If we run this example, we will see that the first Equals call returns true just as before, but the ReferenceEquals method call returns false, and why is that?

It is telling that both string variables are different instances even though they contain the same data and if you recall what we discussed in previous post that String type overrides Equals method to compare the value of two instance not the reference.

You know that in C# static methods cannot be overridden which means you can never change the behavior of ReferenceEquals method which makes sense because it always needs to do the reference comparison.

Summary

  • We learned how .Net provides the types equality implementation out of the box
  • We saw that few methods are defined by the .Net framework on the Object class which are available for all types .
  • By default the virtual Object.Equals method does reference equality for reference types and value equality for value types by using reflection which is a performance overhead for value types.
  • Any type can override Object.Equals method to change the logic of how it checks for equality e.g. String, Delegate and Tuple do this for providing value equality, even though these are reference types.
  • Object are provides a static Equals method which can be used when there is chance that one or both of the parameters can be null, other than that it behaves identical to the virtual Object.Equals method.
  • There is also a static ReferenceEquals method which provides a guaranteed way to check for reference equality.

Udemy

Story of Equality in .Net - Part 1

Sunday, June 19, 2016 0 Comments A+ a-


Background

Few months back i followed a very interesting course on Pluralsight by Simon Robinson about Equality and Comprison in .Net which is a great course indeed that would help developers to understand that how equlity and comparisons work in .Net, So i thought to shared the insights of it what i have learned from the course, hope this will help others to understand the equality behaviour and in depth understnading of how .Net handles it.

Introduction

The purpose of this post is to outline and explore some of the issues that makes performing the equality much more complex than you might expect. Among other things, we will examine the difference between the value and reference equality and why equality and inheritance don’t work well together. So let’s get started.

We will start from a simple example that will compare two numbers. For instance let’s say that 3 is less than 4, conceptually it is trivial and the code for that is also very easy and simple:

   if(3 < 4)
   {
            
   }



If you look at the System.Object class from which all other types inherit, you will find the following 4 methods which are for equality checking:


In addition to that Microsoft has provided 9 different interfaces for performing equality or comparison of types:

Most of these method and interfaces come with a risk that if you override their implementation incorrectly, it will cause bugs in your code and can will also break the existing collections provided by the framework which depend on them

We will see what’s the purpose of these method and interfaces is and how to use these them correctly. We will also focus on How to provide custom implementation for equality and comparisons in the right way, which will perform efficiently and follows best practices and most importantly does not break other types implementation.

Equality is Difficult

  There are 4 reasons that make equality complex than you might expect:
1.           Reference v/s Value Equality
2.          Multiple ways to Compare Values
3.         Accuracy
4.        Conflict with OOP

Reference V/S Value Equality

There is an issue of reference versus value equality, it’s possible to treat equality either way and unfortunately c# is not being designed in a way so that it can distinguish between two of these and that can cause unexpected behavior sometimes, if you don’t understand how these various operators and method work.
As you know, in C# reference types do not contain actual value, they contains a pointer to a location in memory that actually holds those values, which means that for reference types there are two possible ways to measure the equality.
You can say that do both variables refer to same location in memory which is called reference equality and known as Identity or you can say that do the location to which both variables are pointing contains the same value, even if they are different locations which is called Value Equality.

We can illustrate the above points using the following example:

class Program
{
 
    static void Main(String[] args)
    {
        Person p1 = new Person();
        p1.Name = "Ehsan Sajjad";
 
        Person p2 = new Person();
        p2.Name = "Ehsan Sajjad";
 
        Console.WriteLine(p1 == p2);
        Console.ReadKey();
    }     
 
}



As you can see in the above example, we have instantiated two objects of Person class and both contains the same value for Name property, clearly the above two instances of Person class are identical as they contain the same values, are they really equal? When we check their equality of both instances using c# equality operator and runt the example code, it prints out on the console False as output, which means that they are not equal.



It is because for Person class both C# and the .Net framework considers the equality to be the Reference Equality. In other words, the Equality operator checks whether these two variable refer to the same location in memory, so in this example, they are not equal because though both instances of Person class are identical but they are separate instances, the variables p1 and p2 both refer to different locations in memory.

Reference Equality is very quick to perform, because you only need to check for one thing whether the two variable holds the same memory address, while comparing values can be a lot slower.

For Example, if Person class holds a lot of fields and properties instead of just one, and if you wanted to check if the two instances of Person class have same values, you will have to check every field/property, there is no operator in C# which would check the value equality of two Person class instances which is reasonable though, because comparing two instances of Person class containing exactly the same values is not the sort of thing you would normally want to do, obviously if for some reason you would want to do that you will need to write your own code to do that.


Now take this code as example:

class Program
{
 
    static void Main(String[] args)
    {
        string s1 = "Ehsan Sajjad";
 
        string s2 = string.Copy(s1);
 
        Console.WriteLine(s1 == s2);
        Console.ReadKey();
     }     
 
 }

The above code is quite similar to previous example code, but in this case we are applying equality operator on to identical strings, we instantiated a string and stored it’s reference in a variable named s1, then we created copy of its value and hold that in another variable s2, now if we run this code, we will see that according to output we can say that both strings are equal.



If the equality operator had been checking for reference equality, we would had seen false printed on the console for this program, but for strings == operator evaluates equality of values of the operands.

Microsoft has implemented it like that, because checking whether one string contains another string is something a programmer would very often need to do.

Reference and Value Types

The reference and value issue only exists for Reference Types by the way. For unboxed value types for such as integer, float etc the variable directly contains the value, there are no references which means that equality only means to compare values.

The following code which compares two integers will evaluate that both are equal, as the equality operator will compare the values that are hold by the variables.
 
class Program
{
 
    static void Main(String[] args)
    {
        int num1 = 2;
 
        int num2 = 2;
 
        Console.WriteLine(num1 == num2);
 
        Console.ReadKey();
    }     
 
}


So in the above code the equality operator is comparing the value stored in variable num1 with the value stored in num2.

However if we modify this code and cast both variables to object, as we did in the following lines of code:
int num1 = 2;
 
  int num2 = 2;
 
  Console.WriteLine((object)num1 == (object)num2);



Now if we run the code, you will see that the result in contradictory with the result we got from the first version of code, which is the second version of code comparison returns false, that happened because the object is a reference type, so when we cast integer to object, it ends up boxed in to object as reference, which means the second code is comparing references not values and it returns false because both integers are boxed in to different reference instances.

This is something that a lot of developers don’t expect, normally we don’t cast value types to object, but there is another common scenario that we often see is that if we need to cast value type in to an interface.

Console.WriteLine((IComparable)num1 == (IComparable)num2);


For illustrating what we said above, let’s modify the example code to cast the integer variables to ICompareable<int>. This is an interface provided by .Net framework which integer type inherits or implements, we will talk about it in some other post about it.

In .Net interfaces are always reference types, so the above line of code involves boxing too, and if we run this code, we will see that this equality check also returns false, and it’s because this is again checking reference equality.

So, you need to be careful when casting values types to interfaces, it will always result in reference equality if you do equality check.

== Operator

All this code would probably not had been a problem, if C# had different operators for value-types and reference types equality, but it does not, which some developers think is a problem. C# has just one equality operator and there is no obvious way to tell upfront what the operator is actually going to do for a given type.
For instance consider this line of code:

Console.WriteLine(var1 == var2)


We cannot tell what the equality operator will do in the above, because you just have to know what equality operator does for a type, there is no way around, that’s how C# is designed.

In this post we will go through, what the equality operator does and how it works under the hood in detail, so after reading the complete post, I hope you will have a much better understanding than other developers that what actually happens when you write an equality check condition and you will be better able to tell how equality between two objects is evaluated and will be able to answer correctly whenever you came across the code where two objects are being compared for equality.

Different Ways to Compare Values

Another issue that exists in that complexity of equality is, there are often more than one ways to compare values of a given type. String type is the best example for this. Suppose we have two string variable the contain the same value in them:

   string s1 = "Equality";
 
   string s2 = " Equality";


Now if compare both s1 and s2, should we expect that the result would be true for equality check? Means should we consider these two variables to be equal?
I am sure you are looking as both string variables contains exactly same values, then it makes sense to consider them equal, and indeed that is what c# does, but what if I change the case of one of them to make them different  like:

   string s1 = "EQUALITY";
 
   string s2 = "equality";

Now should these two strings to be considered equal? In C# the equality operator will evaluate to false saying that the two strings are not equal, but if we are not asking about C# equality operator, but about in Principle we should consider those two strings as equal then we cannot really answer, as it completely depends on the context whether we should consider or ignore the case, Let’s say I have a database of food items, and we are querying a food item to be searched from database, then the changes are we want to ignore the case and treat the both string equal, but if the user is typing in password for logging in to an application, and you have to check if the password entered by user is correct, then you should not certainly consider the lower case and title case strings to be equal.

The equality operator for strings in C# is always case sensitive, so you can’t use it for comparison and ignore the case. If you want to ignore the case, you can do but you will have to call the special methods which are defined in the String type. For Example:

  
  string s1 = "EQUALITY";
 
  string s2 = "equality";

  if(s1.Equals(s2,StringComparison.OrdinalIgnoreCase))


The above example will evaluate if statement to true as we are telling to ignore the case when doing comparison for equality between s1 and s2.

Now I am sure that none of that will surprise you. Case sensitivity is an issue that almost everyone encounters very early on when they do programming. From the above example we can illustrate a wider point for equality in general that Equality is not absolute in programming, it is often context-sensitive (e.g. case-sensitivity of string)

One example of this is that user is searching for an item on a shopping cart web application and user types an item name with extra whitespace in it, but when we are comparing that with items in our database, so should we consider the item in our database equal to the item entered by user with whitespace, normally we consider them equal and display that result to user as a result of searching, which again illustrates that equality is context sensitive.

Let’s take one more example, consider the following two database records:



Are the equal? In one sense Yes. Obviously these are the same records, they refer to the same drink item and they have the same primary key, but couple of columns value are different, it is clear that the second records item is the data after the records was updated and the first one is before updating, so this illustrates another conceptual issue with equality which comes in to play when you are updating data. Do you care about the precise values of the record or do you care whether it is the same record and clearly there is no one right answer to that. So once again it depends on the context what you are trying to do!

Equality and Comparison

The way .Net deals with multiple meanings of equality is quite neat. .Net allows each type to specify its own single natural way of measuring equality for that type. So, for example, String type defines it’s natural equality to be if two strings contains exactly same sequence of characters, that’s why comparing two strings with different case returns false as they contains different character. This is because “eqaulity” is not equal to “EQUALITY” as lower case and uppercase are different characters.

It is very common that the types expose their natural way of determining equality by means of a generic interface called IEquatable<T>. String also implements this interface for equality. But separately .Net also provides a mechanism for you to plug in a different implementation of equality if you don’t like the Type’s own definition or if that does not fulfill your needs.

This mechanism is based on what is known as Equality Comparers. An Equality Comparer is an object whose purpose is to test whether instances of a type are equal using the definition provided by the comparer for checking equality.

Equality Comparers implement an interface called IEqualityComparer<T>. So for example, if you want to compare string ignoring the extra whitespaces, you could write an equity comparer that knows how to do that and then use that equality comparer instead of the equality operator as required.

Things work basically the same way for doing ordering comparisons. The main difference is that you would use different interfaces.  .Net also provides an interface to provide mechanism for a type to do less than or greater then comparison for a type which is known as ICompareable<T>, and separately you can write what are known as comparers which is IComparer<T>, this can be used to define an alternative implementation for comparison done for ordering, we will see how to implement these interfaces in some other post.

Equality for Floating Points

Some data types are inherently approximate. In .Net you will encounter this problem with floating point types like float, double or decimal or any type that contains a floating point type as a member field. Let’s have a look on an example.
 

    
    float num1 = 2.000000f;
    float num2 = 2.000001f;
    Console.WriteLine(num1 == num2);

We have two floating point numbers that are nearly equal. So are they equal? It looks pretty obvious that they are not equal as they differ in the final digit and we are printing the equality result on console, so when we run the code, the program displays true

This program has come out saying that they both are equal which is completely contradictory to what we have evaluated by looking at the numbers and you can probably guess what the problem is. Computers can only the numbers to a certain level of accuracy and the float type just cannot store the enough significant digits to distinguish these two particular numbers and it can work other way around two, see this example:


    
    float num1 = 1.05f;
    float num2 = 0.95f;
 
    var sum = num1 + num2;

    Console.WriteLine(sum);
    Console.WriteLine(sum == 2.0f);


This is a simple calculation where we are adding 1.05 to 0.95. It looks very obvious that when you add those two numbers you will get the answer 2.0, so we have written a small program for this which adds those two numbers and then we check that the sum of two numbers is equal to 2.0, if we run the program, the output contradicts what we had thought, which says the sum is not equal to 2.0, the reason is that rounding errors happened in the floating point arithmetic resulting in the answer storing a number that is very close to 2, so close that string representation on Console.WriteLine even displayed it as 2 but it’s still not quite equal to 2.


Those rounding errors in floating point arithmetic has resulted in the program to give the opposite answer to what any common sense reasoning would tell you. Now this is an inherent difficulty with the floating point numbers. Rounding error means that testing for equality often give you the wrong result and .Net has no solution for this. The recommendation is, you don’t try to compare floating point numbers for equality because the results might not be what you predict. This only applies to equality, this problem does not normally affect the less than an greater than comparisons, in most cases there are no problems with comparing the floating points number to see whether one is greater than or less than another , it’s equality that gives the problem.

Equality Conflict with Object Oriented Principles

This one often comes to as a surprise to experienced developers as well, there is in fact a fundamental conflict between equality comparisons, type safety and good object oriented practices. These 3 things do not sit well together, this often makes very hard to make equality right and bug free even once you resolved the other issues.

We will not talk much about this in details as it will be easy for you to understand once we start seriously coding which I will demonstrate in a separate post and you will be able to then how the problem naturally arises in the code you right.

Now let’s just try and give you a rough idea of the conflict for now. Let’s say we have base class Animal which represents different animals and will have a derived class for example Dog which adds information specific to the Dog.

      public class Animal
      {
 
      }
 
      public class Dog : Animal
      {
 
      }

If we wanted the Animal class to declare that Animal instances know how to check whether they are equal to other Animal instances, you might attempt to have it implement IEquatable<Animal>. This requires it to implement an Equals() method which takes an Animal instance as a parameter .

    
     public class Animal : IEquatable<animal>
     {
 
        public virtual bool Equals(Animal other)
        {
            throw new NotImplementedException();
        }
    }


If we  want Dog class  to also declare that Dog instances know how to check wether they are equal to other Dog instances, we probably have implement IEquatable<Dog>  that means it will also implement similar  Equals() method  which take Dog instance as parameter.

    public class Dog : Animal, IEquatable<Dog>
    {
 
        public virtual bool Equals(Dog other)
        {
            throw new NotImplementedException();
        }
    }


And this is where the problem comes in. You can probably guess that in a well-designed OOP code, you would expect the Dog class to override the Equals() method of Animal class, but the trouble is Dog equals method  has a different argument parameter  than Animal Equals method which means it won’t override it and if you are not very careful  that can cause sort of subtle bugs where you end up calling the wrong equals method and so returning the wrong result.

Often the only work around to this lose type-safety and that’s what you exactly see in the Object type Equals method  which is the most basic way most types implement equality.


   class Object
   {
       public virtual bool Equals(object obj)
       {
     
       }
    
   }


This method takes an instance of object type as parameter which means it is not type-safe, but it will work correct with inheritance. This is a problem that is not well-known, there were a few blogs around that gave incorrect advice on how to implement equality because they don’t take account of this issue, but it is a problem there. We should be very careful how we design our code to avoid it.

Summary

  • C# does not syntactically distinguish between value and reference equality which means it can sometimes be difficult to predict what the equality operator will do in particular situations. 
  •   There are often multiple different ways of legitimately comparing values. .Net addresses this by allowing types to specify their preferred natural way to compare for equality, also providing a mechanism to write equality comparers that allow you to place a default equality for each type
  • It is not recommended to test floating point values for equality because rounding errors can make this unreliable
  • There is an inherent conflict between implementing equality, type-safety and good Object Oriented practices.