Equal Consistency

From NDjango
Jump to: navigation, search

Issue description

Several tags check 2 parameters for equality. The behavior should be consistent. Tags involved: ifchanged, ifequal, ifnotequal

At this time these two values are resolved into Some obj v1 and Some obj v2

After that - following code is used to choose true/false branch

<source lang="ocaml">

   match v1,v2 with
   | None,_ | _, None -> node_list_false
   | Some value1, Some value2 -> 
       if not = value1.Equals value2 
           then node_list_true
           else node_list_false

</source>

so, at this time we use object.Equals method to check for equality. In some cases it works fine because:


The default implementation of Equals supports reference equality for reference types, and bitwise equality for value types. Reference equality means the object references that are compared refer to the same object. Bitwise equality means the objects that are compared have the same binary representation. (c) MSDN


The problem comes when someone gives parameters of different types (as example Int16 and Int32). - .Equals return false

Why that happens

in C#/.net (Int16var == Int32var) == true, because of numeric promotion. numeric promotion rules are applied at compile time to convert input paremeters and choose most approptiate operator (in that case == operator of appropriate type)

It seems to be impossible to get the same behaviour easily during runtime on two objects using .Equals; .CompareTo, etc...


The rules are as follows: ((c) C# reference, 7.2.6)

1)    If either operand is of type decimal, the other operand is converted to type decimal, or a compile-time error occurs if the other operand is of type float or double.
2)    Otherwise, if either operand is of type double, the other operand is converted to type double.
3)    Otherwise, if either operand is of type float, the other operand is converted to type float.
4)    Otherwise, if either operand is of type ulong, the other operand is converted to type ulong, or a compile-time error occurs if the other operand is of type sbyte, short, int, or long.
5)    Otherwise, if either operand is of type long, the other operand is converted to type long.
6)    Otherwise, if either operand is of type uint and the other operand is of type sbyte, short, or int, both operands are converted to type long.
7)    Otherwise, if either operand is of type uint, the other operand is converted to type uint.
8)    Otherwise, both operands are converted to type int.

Django python implementation

From python docs:

The operators <, >, ==, >=, <=, and != compare the values of two objects. The objects need not have the same type. If both are numbers, they are converted to a common type.

Since IfEqual uses == and != operators in python implementation - it looks that django implementation has no such issues.

What should be done

We should make a function, which will implement the same behaviour as in these rules for numeric valuetypes.

For the rest of valuetypes - it's better to cast these to System.ValueType and use ValueType.Equals, since it has better comparison algorithm ( it's from .net documentation)

luckily - there are not so many base value-types, so there are some options on implementation -Byte,SByte,Int16,Int32,Int64,UInt16,UInt32,UInt64,Single,Double,Boolean,Char,Decimal