Nullable trilogy part II: a == b -> a>=b && a


A question that of­ten comes up when we dis­cuss Nullable  is about the anti-sym­met­ric prop­erty. This prop­erty states that if a==b then a>=b and a<=b. If a and b are null then this prop­erty is not sat­is­fied in the cur­rent de­sign as the re­sult of >= and <= is al­ways false when one of the pa­ra­me­ters is null. This may seems sur­pris­ing, but it can be eas­ily un­der­stood when con­sid­er­ing if null can be or­dered.

We de­cided that null be­ing less of (or more of) all the other el­e­ments in the do­main would be an ar­bi­trary de­ci­sion and as such null can­not be or­dered. If it can­not be or­dered then the re­sult of the re­la­tional op­er­a­tors for null is false as these op­er­a­tors can be de­fined as:

  a<b -> ordered(a,b) && a<b

  a<=b -> ordered(a,b) && (a<b || a==b)

It might be ar­gued that for prac­ti­cal rea­sons it is con­ve­nient to have the <= and >= op­er­a­tors re­turn true in case null is on both sides, but this choice has some prac­ti­cal draw­backs. Consider the fol­low­ing code:

    void ProcessTransactions(int?[] transactions, int? maxValue) {
    foreach(int? t in transactions)
      if(t < maxValue) ProcessTransaction(t);

This code does what the pro­gram­mer ex­pects, even when max­Value is null (in which case it won’t process any el­e­ment). Now let’s sup­pose that the pro­gram­mer changes his mind and wants to in­clude max­Value in the pro­cess­ing. He will then change the <’ op­er­a­tor to be <=’.

Under the cur­rent de­sign he will ob­tain what he ex­pects, even in the case max­Value is null. By con­sid­er­ing null >= null as true, this func­tion would sud­denly start pro­cess­ing all the null trans­ac­tions, which is not what the pro­gram­mer in­tended. The prob­lem here is that peo­ple tend to think about the >=’ and <=’ op­er­a­tors as a way to in­clude the limit value in the set of things to be processed. Very rarely, they in­tend to process the null value as well. Another way to think about it is that: de­cid­ing that null can­not be or­dered im­plies that >= has to re­turn false to be con­cep­tu­ally con­sis­tent and to pre­vent these quite sub­tle bugs to oc­cur.