{"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\u2019s been quite a long time since I wrote something on this blog\u2026 Two things occurred that made me do this.<br \/>\nFirstly, I\u2019m going to talk at <a href=\"http:\/\/jdc2013.egjug.org\/\">Java Developer\u2019s 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\u2019s 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\u2019ve left some stuff out, so now it looks too complex for it\u2019s task):<\/p>\n<pre class=\"brush:scala\"><code>def findDates(dates:SortedSet[DateTime],a:List[DateTime])=\r\n  if (dates.isEmpty || dates.head.toMilis < 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 \u2013 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 \u201cstrangely\u201d 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\u2019s 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 \u2013 in our data there were dates that were equal with respect to miliseconds, but in different timezones. What\u2019s more, not every pair of such dates can lead to disaster. They have to cause some mess in underlying black-red tree\u2026 The solution was to introduce some wrapper (we used it anyway actually) that defined comparison consistent with equality\u2026<\/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}]}}