{"id":11033,"date":"2013-02-16T16:32:00","date_gmt":"2013-02-16T15:32:00","guid":{"rendered":"http:\/\/touk.pl\/blog\/?guid=828de32673e802404004cee94c6eef57"},"modified":"2022-08-03T12:48:57","modified_gmt":"2022-08-03T10:48:57","slug":"sortedset-joda-datetime-danger","status":"publish","type":"post","link":"https:\/\/touk.pl\/blog\/2013\/02\/16\/sortedset-joda-datetime-danger\/","title":{"rendered":"SortedSet + Joda DateTime == danger"},"content":{"rendered":"<div dir=\"ltr\" style=\"text-align: left\">\n<p>It&#8217;s been quite a long time since I wrote something on this blog&#8230; Two things occurred that made me do this.<br \/>\nFirstly, I&#8217;m going to talk at <a href=\"http:\/\/jdc2013.egjug.org\/\">Java Developer&#8217;s Conference<\/a> in Cairo and at <a href=\"http:\/\/boosterconf.no\/\">Booster conference<\/a> in Bergen next month, so I want to have some content when I put a link at my slides ;)<br \/>\nSecondly, last week I encountered really weird situation. In fact it was endless loop.<br \/>\nYep.<br \/>\nIn was in rather critical place of our app and it was on semi-production environment so it was quite embarassing. What&#8217;s more, the code was working before, it was untouched for about half a year, and it had pretty good test coverage. It looked more or less like this (I&#8217;ve left some stuff out, so now it looks too complex for it&#8217;s task):<\/p>\n<pre class=\"brush:scala\"><code>def findDates(dates:SortedSet[DateTime],a:List[DateTime])=\r\n  if (dates.isEmpty || dates.head.toMilis &lt; date) {\r\n    (dates, a)\r\n  } else {\r\n    findDates(dates - dates.head, a+dates.head)\r\n  }\r\n<\/code><\/pre>\n<p>Just simple tail recursion, how can it loop endlessly? It turns out it can. Actually, for some specific data <b>dates &#8211; dates.head == dates<\/b>.<br \/>\nWhy? The reason is DateTime is not consistent with equals. If you look into Comparable definition, it says:<\/p>\n<blockquote><p>It is strongly recommended (though not required) that natural orderings be consistent with equals. This is so because sorted sets (and sorted maps) without explicit comparators behave &#8220;strangely&#8221; when they are used with elements (or keys) whose natural ordering is inconsistent with equals. In particular, such a sorted set (or sorted map) violates the general contract for set (or map), which is defined in terms of the equals method.<\/p><\/blockquote>\n<p>What does this mean? That you should only use sorted collections for classes that satisfy following:<b>if a.compareTo(b) == 0 then a.equals(b) == true <\/b>And in joda&#8217;s DateTime javadoc you can read:<\/p>\n<blockquote><p>Compares this object with the specified object for ascending millisecond instant order. This ordering is inconsistent with equals, as it ignores the Chronology.<\/p><\/blockquote>\n<p>And it turns out that this was our case &#8211; in our data there were dates that were equal with respect to miliseconds, but in different timezones. What&#8217;s more, not every pair of such dates can lead to disaster. They have to cause some mess in underlying black-red tree&#8230; The solution was to introduce some wrapper (we used it anyway actually) that defined comparison consistent with equality&#8230;<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"It&#8217;s been quite a long time since I wrote something on this blog&#8230;  Two things occurred that made me do this.  Firstly, I&#8217;m going to talk at Java Developer&#8217;s Conference in Cairo and at Booster conference in Bergen next month, so I want to have some co&#8230;\n","protected":false},"author":4,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11],"tags":[],"class_list":{"0":"post-11033","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-development-design"},"_links":{"self":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/11033","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/comments?post=11033"}],"version-history":[{"count":6,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/11033\/revisions"}],"predecessor-version":[{"id":14931,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/11033\/revisions\/14931"}],"wp:attachment":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/media?parent=11033"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/categories?post=11033"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/tags?post=11033"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}