<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>The Compare Contract [Kim Hamilton]</title><link>http://blogs.msdn.com/bclteam/archive/2008/10/06/the-compare-contract-kim-hamilton.aspx</link><description>A breaking change? We recently heard from a customer who observed different sorting behavior in .NET FX 3.5 SP1 compared to 3.5 RTM. The different behavior was demonstrated with the following code. The class StringWrapper provided a custom sort in which</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>  The Compare Contract [Kim Hamilton] : EasyCoded</title><link>http://blogs.msdn.com/bclteam/archive/2008/10/06/the-compare-contract-kim-hamilton.aspx#8977976</link><pubDate>Mon, 06 Oct 2008 18:44:45 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8977976</guid><dc:creator>  The Compare Contract [Kim Hamilton] : EasyCoded</dc:creator><description>&lt;p&gt;PingBack from &lt;a rel="nofollow" target="_new" href="http://www.easycoded.com/the-compare-contract-kim-hamilton/"&gt;http://www.easycoded.com/the-compare-contract-kim-hamilton/&lt;/a&gt;&lt;/p&gt;
</description></item><item><title>Does this apply to System.Comparison&lt;T&gt;?</title><link>http://blogs.msdn.com/bclteam/archive/2008/10/06/the-compare-contract-kim-hamilton.aspx#8984281</link><pubDate>Tue, 07 Oct 2008 14:14:09 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8984281</guid><dc:creator>Kalle Olavi Niemitalo</dc:creator><description>&lt;p&gt;This requirement treat nulls as the smallest values is documented as applying to:&lt;/p&gt;
&lt;p&gt;- System.IComparable.CompareTo&lt;/p&gt;
&lt;p&gt;- System.IComparable&amp;lt;T&amp;gt;.CompareTo&lt;/p&gt;
&lt;p&gt;- System.Collections.IComparer.Compare&lt;/p&gt;
&lt;p&gt;- System.Collections.Generic.IComparer&amp;lt;T&amp;gt;.Compare&lt;/p&gt;
&lt;p&gt;But does it apply to the System.Comparison&amp;lt;T&amp;gt; delegate? &amp;nbsp;The documentation does not say.&lt;/p&gt;
</description></item><item><title>re: The Compare Contract [Kim Hamilton]</title><link>http://blogs.msdn.com/bclteam/archive/2008/10/06/the-compare-contract-kim-hamilton.aspx#8988534</link><pubDate>Wed, 08 Oct 2008 02:13:24 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8988534</guid><dc:creator>Simone Busoli</dc:creator><description>&lt;p&gt;Of course it doesn't Kalle, since it accepts two arguments and you can perform any sorting you like there.&lt;/p&gt;
</description></item><item><title>re: The Compare Contract [Kim Hamilton]</title><link>http://blogs.msdn.com/bclteam/archive/2008/10/06/the-compare-contract-kim-hamilton.aspx#8990884</link><pubDate>Wed, 08 Oct 2008 09:47:23 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8990884</guid><dc:creator>Kalle Olavi Niemitalo</dc:creator><description>&lt;p&gt;IComparer.Compare and IComparer&amp;lt;T&amp;gt;.Compare accept two arguments too, yet they have the same requirement. &amp;nbsp;I can understand that nulls must be treated specially in IComparable and IComparable&amp;lt;T&amp;gt;, because it is not possible to call ((IComparable)a).Compare(b) when a is null. &amp;nbsp;In IComparer and IComparer&amp;lt;T&amp;gt; however, either parameter could easily be null. &amp;nbsp;I don't see any reason to require IComparer and IComparer&amp;lt;T&amp;gt; to sort nulls first, but the documentation requires that anyway. &amp;nbsp;And it seems quite odd to me if Comparison&amp;lt;T&amp;gt; and IComparer&amp;lt;T&amp;gt;.Compare have different requirements.&lt;/p&gt;
</description></item><item><title>re: The Compare Contract [Kim Hamilton]</title><link>http://blogs.msdn.com/bclteam/archive/2008/10/06/the-compare-contract-kim-hamilton.aspx#8990976</link><pubDate>Wed, 08 Oct 2008 10:33:26 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8990976</guid><dc:creator>Simone Busoli</dc:creator><description>&lt;p&gt;Yes, that's what I mean. Since the CompareTo is an instance method it won't be called on nulls.&lt;/p&gt;
&lt;p&gt;IComparer&amp;lt;T&amp;gt; and Comparison&amp;lt;T&amp;gt;, be it odd or not, behave differently. Try it yourself:&lt;/p&gt;
&lt;p&gt;using System;&lt;/p&gt;
&lt;p&gt;using System.Collections.Generic;&lt;/p&gt;
&lt;p&gt;public class StringWrapper : IComparable&amp;lt;StringWrapper&amp;gt;&lt;/p&gt;
&lt;p&gt;{&lt;/p&gt;
&lt;p&gt;	public string Value { get; set; }&lt;/p&gt;
&lt;p&gt;	public StringWrapper(string value)&lt;/p&gt;
&lt;p&gt;	{&lt;/p&gt;
&lt;p&gt;		Value = value;&lt;/p&gt;
&lt;p&gt;	}&lt;/p&gt;
&lt;p&gt;	public int CompareTo(StringWrapper other)&lt;/p&gt;
&lt;p&gt;	{&lt;/p&gt;
&lt;p&gt;		if(other == null)&lt;/p&gt;
&lt;p&gt;			return -1;&lt;/p&gt;
&lt;p&gt;		return Value.CompareTo(other.Value);&lt;/p&gt;
&lt;p&gt;	}&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;public class MyComparer : IComparer&amp;lt;StringWrapper&amp;gt;&lt;/p&gt;
&lt;p&gt;{&lt;/p&gt;
&lt;p&gt;	public int Compare(StringWrapper first, StringWrapper second)&lt;/p&gt;
&lt;p&gt;	{&lt;/p&gt;
&lt;p&gt;		if(first == null)&lt;/p&gt;
&lt;p&gt;			return 1;&lt;/p&gt;
&lt;p&gt;		if(second == null)&lt;/p&gt;
&lt;p&gt;			return -1;&lt;/p&gt;
&lt;p&gt;		return first.Value.CompareTo(second.Value);&lt;/p&gt;
&lt;p&gt;	}&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;public class MyClass&lt;/p&gt;
&lt;p&gt;{&lt;/p&gt;
&lt;p&gt;	public static void Main()&lt;/p&gt;
&lt;p&gt;	{&lt;/p&gt;
&lt;p&gt;		StringWrapper a = new StringWrapper(&amp;quot;a&amp;quot;);&lt;/p&gt;
&lt;p&gt;		StringWrapper b = new StringWrapper(&amp;quot;b&amp;quot;);&lt;/p&gt;
&lt;p&gt;		StringWrapper c = new StringWrapper(&amp;quot;c&amp;quot;);&lt;/p&gt;
&lt;p&gt;		StringWrapper d = null;&lt;/p&gt;
&lt;p&gt;		StringWrapper e = new StringWrapper(&amp;quot;e&amp;quot;);&lt;/p&gt;
&lt;p&gt;		StringWrapper f = null;&lt;/p&gt;
&lt;p&gt;		var array1 = new[] {e, c, f, b, d, a};&lt;/p&gt;
&lt;p&gt;		var array2 = new[] {e, c, f, b, d, a};&lt;/p&gt;
&lt;p&gt;		var array3 = new[] {e, c, f, b, d, a};&lt;/p&gt;
&lt;p&gt;		Array.Sort(array1);&lt;/p&gt;
&lt;p&gt;		foreach(var el in array1)&lt;/p&gt;
&lt;p&gt;			WL(el != null ? el.Value : &amp;quot;null&amp;quot;);&lt;/p&gt;
&lt;p&gt;		WL(&amp;quot;&amp;quot;);&lt;/p&gt;
&lt;p&gt;		Array.Sort(array2, new MyComparer());&lt;/p&gt;
&lt;p&gt;		foreach(var el in array2)&lt;/p&gt;
&lt;p&gt;			WL(el != null ? el.Value : &amp;quot;null&amp;quot;);&lt;/p&gt;
&lt;p&gt;		WL(&amp;quot;&amp;quot;);&lt;/p&gt;
&lt;p&gt;		Array.Sort(array3, new MyComparer().Compare);&lt;/p&gt;
&lt;p&gt;		foreach(var el in array3)&lt;/p&gt;
&lt;p&gt;			WL(el != null ? el.Value : &amp;quot;null&amp;quot;);&lt;/p&gt;
&lt;p&gt;	}&lt;/p&gt;
&lt;p&gt;	private static void WL(string text)&lt;/p&gt;
&lt;p&gt;	{&lt;/p&gt;
&lt;p&gt;		Console.WriteLine(text);	&lt;/p&gt;
&lt;p&gt;	}&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
</description></item><item><title>re: The Compare Contract [Kim Hamilton]</title><link>http://blogs.msdn.com/bclteam/archive/2008/10/06/the-compare-contract-kim-hamilton.aspx#8991191</link><pubDate>Wed, 08 Oct 2008 14:52:19 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8991191</guid><dc:creator>daniel_lidstrom</dc:creator><description>&lt;p&gt;Hi Kim, it was enjoyable to get some insights into the BCL. I've been looking through some of the xml classes and I would love to know more about their internal design. I realize this is not the right place to ask, but do you know a better place?&lt;/p&gt;
&lt;p&gt;For example, I'd like to know why XmlTextReader has an internal class called XmlTextReaderImpl.&lt;/p&gt;
&lt;p&gt;Thanks in advance!&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;
&lt;p&gt;Daniel Lidstr&amp;#246;m,&lt;/p&gt;
&lt;p&gt;Stockholm, Sweden&lt;/p&gt;
</description></item><item><title>re: The Compare Contract [Kim Hamilton]</title><link>http://blogs.msdn.com/bclteam/archive/2008/10/06/the-compare-contract-kim-hamilton.aspx#8993197</link><pubDate>Thu, 09 Oct 2008 22:32:25 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8993197</guid><dc:creator>Kim Hamilton</dc:creator><description>&lt;p&gt;Hi Kalle and Simone,&lt;/p&gt;
&lt;p&gt;Sorry for the delay. It's correct that, with IComparables, nulls may be special cased to avoid calling CompareTo on null.&lt;/p&gt;
&lt;p&gt;If you specify a comparer other than the default comparer, then that comparer will be used. &lt;/p&gt;
&lt;p&gt;Simone - are you saying when you run that repro you get different results for IComparer&amp;lt;T&amp;gt; and Comparison&amp;lt;T&amp;gt;? I get the same output, i.e.:&lt;/p&gt;
&lt;p&gt;a, b, c, e, null, null&lt;/p&gt;
&lt;p&gt;Let me know if you're seeing different behavior.&lt;/p&gt;
&lt;p&gt;To get back to the original question: I'm not sure why our docs say this requirement for IComparer and IComparer&amp;lt;T&amp;gt;, because no special cases are being made. My guess is it's either a doc error or based on an earlier assumption that IComparers should always do this. I'll look into this and reply.&lt;/p&gt;
&lt;p&gt;Thanks,&lt;/p&gt;
&lt;p&gt;Kim&lt;/p&gt;
</description></item><item><title>re: The Compare Contract [Kim Hamilton]</title><link>http://blogs.msdn.com/bclteam/archive/2008/10/06/the-compare-contract-kim-hamilton.aspx#8994971</link><pubDate>Sat, 11 Oct 2008 01:11:46 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8994971</guid><dc:creator>Simone Busoli
</dc:creator><description>&lt;p&gt;@Kim&lt;/p&gt;
&lt;p&gt;no I'm not saying that IComparer and Comparison have different behavior, quite the opposite. I mean that they have different behavior compared to IComparable, that is, they can sort nulls correctly.&lt;/p&gt;
&lt;p&gt;The docs of IComparer&amp;lt;T&amp;gt;.Compare method say:&lt;/p&gt;
&lt;p&gt;A null reference is considered to be less than any reference that is not null.&lt;/p&gt;
&lt;p&gt;To me, this doesn't mean anything. I am doing the custom sorting, so who is considering null references less than non null references?&lt;/p&gt;
</description></item><item><title>re: The Compare Contract [Kim Hamilton]</title><link>http://blogs.msdn.com/bclteam/archive/2008/10/06/the-compare-contract-kim-hamilton.aspx#8996942</link><pubDate>Mon, 13 Oct 2008 01:17:34 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8996942</guid><dc:creator>slorion</dc:creator><description>&lt;p&gt;Let's say we want to sort a List&amp;lt;T&amp;gt; and put null values at the end, how can we achieve that goal then ? Seems to me that you impose a non obvious semantic contract for the sake of performance only.&lt;/p&gt;
&lt;p&gt;IComparable, IEquatable and others similar interfaces are broken anyway as their behavior on null is undefined. IMO a functional approach would have been much better (ie Comparison&amp;lt;T&amp;gt; or even IComparer&amp;lt;T&amp;gt;). &lt;/p&gt;
&lt;p&gt;Why have so many different ways (IEquatable&amp;lt;T&amp;gt;, IEqualityComparer&amp;lt;T&amp;gt;, static and virtual Objects.Equals, Comparison&amp;lt;T&amp;gt; ....) to do something as basic as comparing ? It just makes things complicated, inconsistent and cumbersome. It is particularly annoying when one library cannot &amp;quot;talk&amp;quot; to another because one did not do it the same way as the other.&lt;/p&gt;
</description></item><item><title>re: The Compare Contract [Kim Hamilton]</title><link>http://blogs.msdn.com/bclteam/archive/2008/10/06/the-compare-contract-kim-hamilton.aspx#9008788</link><pubDate>Tue, 21 Oct 2008 09:27:05 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9008788</guid><dc:creator>kimhamil</dc:creator><description>&lt;p&gt;I did some detective work and have a recommendation about the Comparison&amp;lt;T&amp;gt; delegate discrepancy. But to make sure we’re all on the same page, I’ll start with a more thorough description of the problem.&lt;/p&gt;
&lt;p&gt;The docs for IComparable.Compare (generic and nongeneric; signatures below) say null should always compare least; i.e. null is less than any non-null reference. As discussed above, that’s reasonable in this case, since CompareTo is an instance method and one may be null.&lt;/p&gt;
&lt;p&gt;IComparable.CompareTo(Object obj)&lt;/p&gt;
&lt;p&gt;IComparable&amp;lt;T&amp;gt;.CompareTo(T other)&lt;/p&gt;
&lt;p&gt;The docs for IComparer.Compare (generic and non-) also say null should compare least&lt;/p&gt;
&lt;p&gt;IComparer.Compare(Object x, Object y)&lt;/p&gt;
&lt;p&gt;IComparer&amp;lt;T&amp;gt;.Compare(T x, T y)&lt;/p&gt;
&lt;p&gt;Interestingly, the Comparison&amp;lt;T&amp;gt; delegate takes 2 args (like IComparer&amp;lt;T&amp;gt;.Compare), but it doesn’t specify that null should always compare least.&lt;/p&gt;
&lt;p&gt;delegate int Comparison&amp;lt;T&amp;gt;(T x, T y);&lt;/p&gt;
&lt;p&gt;So why does IComparer&amp;lt;T&amp;gt;.Compare say null should compare least but Comparison&amp;lt;T&amp;gt; has no such requirement? &lt;/p&gt;
&lt;p&gt;Unfortunately the history is missing, but the most likely explanation seems to be rooted in the Remarks section for IComparer.Compare (note, non-generic). This says the preferred implementation is to use CompareTo method (from the IComparable interface) of one of the parameters. If this is the case, it makes sense that it would expect parity with IComparable and null should compare least.&lt;/p&gt;
&lt;p&gt;IComparer&amp;lt;T&amp;gt;.Compare (the generic version of above) get trickier. It doesn’t mention that the preferred implementation is to use CompareTo, but it does say null should always compare least.&lt;/p&gt;
&lt;p&gt;As discussed in the comments above, special casing null is a reasonable restriction if the compare method is an instance method on the comparands, one of which may be null. However, this isn’t the case for IComparer, IComparer&amp;lt;T&amp;gt;, and Comparison&amp;lt;T&amp;gt; .&lt;/p&gt;
&lt;p&gt;I think the “preferred implementation” guidance is the only reason IComparer.Compare requires that null compare least. &amp;nbsp;Furthermore, the “preferred implementation” guidance is questionable because it overlooks a key selling point of IComparer – the ability to provide a custom comparison. It’s good that the preferred implementation guidance didn’t carry over to IComparer&amp;lt;T&amp;gt;.Compare. Unfortunately, the requirement to special-case null for IComparer&amp;lt;T&amp;gt;.Compare is inconsistent from this perspective. However, this guidance has been there for a while and possibly the best thing we can do for now is leave this as is. &lt;/p&gt;
&lt;p&gt;Lastly, the IComparison&amp;lt;T&amp;gt; delegate currently has neither restriction. I think we should leave it as is instead of letting legacy restrictions creep around. Why not give the flexibility? Any comments?&lt;/p&gt;
</description></item><item><title>re: The Compare Contract [Kim Hamilton]</title><link>http://blogs.msdn.com/bclteam/archive/2008/10/06/the-compare-contract-kim-hamilton.aspx#9009222</link><pubDate>Tue, 21 Oct 2008 13:57:25 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9009222</guid><dc:creator>Kalle Olavi Niemitalo</dc:creator><description>&lt;p&gt;Certainly the documentation of IComparer.Compare and IComparer&amp;lt;T&amp;gt;.Compare should be clearer on whether nulls first is only a recommendation or a requirement. &amp;nbsp;I think a reasonable compromise would be:&lt;/p&gt;
&lt;p&gt;- At IComparer.Compare and IComparer&amp;lt;T&amp;gt;.Compare, say that these methods were originally intended to treat nulls as the smallest values, and that some callers may require this but the Sort methods included in the .NET Framework do not.&lt;/p&gt;
&lt;p&gt;- At each Sort method that takes an IComparer or IComparer&amp;lt;T&amp;gt; parameter, say whether or not that Sort method expects the comparer to sort nulls first.&lt;/p&gt;
&lt;p&gt;That would leave the interface specification vague but it's better to be vague explicitly than implicitly.&lt;/p&gt;
</description></item><item><title>re: The Compare Contract [Kim Hamilton]</title><link>http://blogs.msdn.com/bclteam/archive/2008/10/06/the-compare-contract-kim-hamilton.aspx#9010108</link><pubDate>Tue, 21 Oct 2008 20:58:23 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9010108</guid><dc:creator>kimhamil</dc:creator><description>&lt;p&gt;Definitely agree that doc clarification is needed -- I'll follow up on this. &lt;/p&gt;
&lt;p&gt;In fact, I like the phrasing of your first bullet. That will reduce confusion for readers who've been through former iterations of guidance.&lt;/p&gt;
&lt;p&gt;Also, perhaps I should rename this post to the CompareTo contract, to avoid further confusion. :)&lt;/p&gt;
</description></item><item><title>re: The Compare Contract [Kim Hamilton]</title><link>http://blogs.msdn.com/bclteam/archive/2008/10/06/the-compare-contract-kim-hamilton.aspx#9010122</link><pubDate>Tue, 21 Oct 2008 21:06:50 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9010122</guid><dc:creator>kimhamil</dc:creator><description>&lt;p&gt;Hi Daniel, &lt;/p&gt;
&lt;p&gt;Sorry for the delay. Have you tried &lt;a rel="nofollow" target="_new" href="http://blogs.msdn.com/xmlteam/?"&gt;http://blogs.msdn.com/xmlteam/?&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Thanks,&lt;/p&gt;
&lt;p&gt;Kim&lt;/p&gt;
</description></item></channel></rss>