The result of calling IEquatable <T> .Equals (T obj) when is == null and obj == null?
What should IEquatable<T>.Equals(T obj) do when this == null and obj == null ?
1) This code is generated by the F # compiler when implementing IEquatable<T> . You can see that it returns true when both objects are null :
public sealed override bool Equals (T obj)
{
if (this == null)
{
return obj == null;
}
if (obj == null)
{
return false;
}
// Code when both this and obj are not null.
}
2) . Similar code can be found in the question " in the implementation of IEquatable is link checking ) or in the question" Is there a complete link to the implementation of IEquatable? ". This code returns false when both objects are null .
public sealed override bool Equals (T obj)
{
if (obj == null)
{
return false;
}
// Code when obj is not null.
}
3) . The final option is to say that the behavior of the method is undefined when this == null .
leppie is right. To give a detailed account of his answer (and to confirm his suspicion that F # does not guarantee this != null) : discriminatory associations can be marked with the attribute [<CompilationRepresentation(CompilationRepresentationFlags.UseNullAsTrueValue)>] , which allows us to consider cases as null. Option<'T> is that type. The None case is represented by zero at runtime. (None : option<int>).Equals(None) syntactically correct. Here is a fun example:
[<CompilationRepresentation(CompilationRepresentationFlags.UseNullAsTrueValue)>] type Maybe<'T> = | Just of 'T | Nothing [<CompilationRepresentation(CompilationRepresentationFlags.Instance)>] member this.ThisIsNull() = match this with Nothing -> true | _ -> false Decompiling ThisIsNull Using Reflector Shows
public bool ThisIsNull() { return (this == null); } And the result:
Nothing.ThisIsNull() //true The reason F # does this (I suspect) is to optimize empty lists as null .
By adding this check, it allows you to easily invoke the instance method on the null instance.
See my blog post after a while.
In C #, this does not matter.
To answer the question:
It should return true , since both instances are null and are considered equal.
If this is null, the code cannot be called, so this case does not need to be considered (in C #, in any case, there are cases when languages ββallow the null object to have a dereferenced method, although it is obvious if it internally examines any of its non-existent fields, this will be an error. Consider:
return x.Equals(y); If x is null, we cannot even call Equals to null check for counting.
Therefore, we only need to consider:
public bool Equals(T obj) { if(obj == null) return false; //logic defining equality here. } If the probability that both objects are equal to zero arises when we study them from a static redefinition of the == operator or from an implementation of IEqualityComparer<T> :
public bool Equals(T x, T y) { if(x == null) return y == null; if(y == null) return false; //logic defining equality here. } Note that here is a useful shortcut, if equality can be long to define (for example, comparing long strings), then we can take advantage of the fact that identity entails equality - this is something that always coincides with itself, even Ayn Rand could figure it out;) There are also algorithms that make comparing an element with itself quite common, which makes this shortcut quite appropriate. In this case, identity comparison already includes checking that both values ββare zero, so we leave this again:
public bool Equals(T x, T y) { if(ReferenceEquals(x, y)) return true; if(x == null || y == null) return false; //logic defining equality here. } For most methods, I assume undefined behavior when called with this==null . This is because most programmers write their code under the assumption that this!=null , which is guaranteed by the C # specification if the calling code is written in C #.
So that every sensible caller x.Equals(y) needs to know for sure that x not null , or add a manual null check.
In most cases, I would not call Equals at all, but instead used EqualityComparer<T>.Default .
I would definitely go with option 1:
if (this == null) { return obj == null; } if (obj == null) { return false; } The null object is always zero.
Sample code is located on MSDN: http://msdn.microsoft.com/en-us/library/ms131190.aspx?ppud=4
If this == null, you will get a runtime exception that calls Equals () for this object.