• Ano (unregistered)

    I don't get this. What is the "well-known problem of DateTime.Parse"?

    What is he trying to do?

  • Anonymous (unregistered)

    Shouldn't the second method be private to stop just anyone calling it?

  • Sharkie (unregistered) in reply to javascript jan
    javascript jan:
    Can't help but think that this behaviour is motivated by some blasphemous non-thread-safety in the date parsing class. So I guess the real WTF is that the date parse takes long enough to prompt a context switch.
    It's funny because my first impression looking at this code was along the same lines.

    I've seen similar hacks that evolved to such silliness by someone getting unexpected results and having to improvise, as their understanding of the REAL problem wasn't easily attainable.

    I'd bet the WTF today is truly some os, language or library issue that yields unexpected behavior and the "hack" is one that a junior found would actually work. We really don't know WHAT the original language was or the whole story, but the code screams such a kludge/work-around commonplace of using lesser mature (cough usually from Redmond, WA cough) platforms or language implementations.

  • Krzys (unregistered)

    Insanity: "Doing the same thing over and over again and expecting different results"

  • (cs)

    In order to understand recursion, you must first understand recursion.

  • AnonCoder (unregistered) in reply to Anon
    Anon:
    Someone You Know:
    You may still be right about the thread-safety thing, but do bear in mind that this isn't Java.
    Yeah, I know, I accidentally edited out the part where I mentioned that WTF entries frequently are "ported" to another language when anonymized, so it's possible that the original was in Java.
    This isn't Java and isn't ported from Java.

    DateFormat and its subclasses do not have static parsing methods in Java. The only reason remotely likely for not getting a new instance each time and running into thread safety issues in Java would be if you were using a specified pattern and wanted to avoid the cost of compiling it per parse. Not the case here.

    In C# DateTime.Parse is static and IS thread safe. Not only is the code idiotic (though not half as much as some of the comments) it is entirely unnecessary.

    Captcha: dubya. Appropriately.

  • Innocent Bystander Passing By (unregistered) in reply to webrunner
    webrunner:
    I once did something like this to fix a mysql error on an extremely stupid server. Once in a while, at random, a mysql call would just fail. If you tried it again right after it'd work fine. So I made it try 5 times, breaking if it fails. If it failed for a legitimate reason it means it wasted some time, but it failed for absolutely no reason just once more often then it failed for reals.

    On course, retrying is often an appropriate way to deal with IO errors. Depending on what it is exactly you are doing, a peripheral may be busy, packets might get lost on a network, and in general external hardware can be expected to display some kind of unpredictability.

    However, if a (non seriouly broken) string parsing function fails once, it will fail in exactly the same way the second or the tenth time.

  • Loren Pechtel (unregistered) in reply to Grant
    Grant:
    The really sad thing is that I am sure this was done for a reason. So, parsing a string to a date may fail, but parsing the exact same string again may succeed. I have seen this, but it was always a memory problem, or something stepping out of bounds and corrupting the memory from other processes.

    This doesn't seem too likely.

    I think it's more likely that the parser itself has a problem either with memory handling or uninitialized data.

    Perhaps they're calling a Microsoft function. I figure there's about a 5% chance that my hotmail password will be rejected as wrong, resubmitting it works. Since it's being autofilled it's not a matter of typos.

  • (cs) in reply to djork
    djork:
    This is ridiculous. Why would you hard-code a maximum of 10 tries into a wonderful method like this? It should really just take a positive integer and move it towards the base case of 0. That way you can specify 10 tries, or 100 tries!

    How un-enterprise-y! It needs to be in an XML config file somewhere!

  • fanha (unregistered)

    Wouldn't this die the second call anyhow if an exception gets thrown during the catch block? It can't possibly recurse more than one layer deep. He might as well have just done infinite recursion.

  • mh (unregistered)

    Of course, DateTime.Parse could be overloaded to run a "select sysdate from dual" against an Oracle database over a high latency/low timeout WAN link, in which case trying again a reasonable number of times is a perfectly valid approach.

  • Jimmy (unregistered) in reply to Josh
    Josh:
    The real WTF is passing the same data to a function and expecting to get different results!

    random.nextInt();

  • Anon (unregistered) in reply to AnonCoder
    AnonCoder:
    Anon:
    Someone You Know:
    You may still be right about the thread-safety thing, but do bear in mind that this isn't Java.
    Yeah, I know, I accidentally edited out the part where I mentioned that WTF entries frequently are "ported" to another language when anonymized, so it's possible that the original was in Java.
    This isn't Java and isn't ported from Java.

    DateFormat and its subclasses do not have static parsing methods in Java. The only reason remotely likely for not getting a new instance each time and running into thread safety issues in Java would be if you were using a specified pattern and wanted to avoid the cost of compiling it per parse. Not the case here.

    In C# DateTime.Parse is static and IS thread safe. Not only is the code idiotic (though not half as much as some of the comments) it is entirely unnecessary.

    Captcha: dubya. Appropriately.

    Unless you can provide the original code, it's still easily possible it was originally in Java and this version has been ported to demonstrate the basic WTF (recursive iteration of the same call).

    In any case, it doesn't change the basic point: this was probably done to work around a race condition. It's still braindead, it's still stupid, it's still a WTF, but presumably the original was done in such a way that it involved a race condition. (Which actually casts doubt on the original being Java - Java's SimpleDateFormat would likely give you a wrong answer rather than throwing an exception.)

    And it's still a WTF that Java has managed to create a date parser/formatter that is not thread safe. It takes a special kind of developer to make non-reentrant methods in an immutable object.

  • Anonymous (unregistered)
    DateTime DateTimeParseSafe(string s)
    {
        DateTime returnVal;
        try
        {
            returnVal = DateTime.Parse(s);
        }
        catch
        {
            returnVal = DateTimeParseSafe("0000-00-00 00:00");  // TODO: Replace with a valid date
        }
        return returnVal;
    }
    
  • AnonCoder (unregistered) in reply to Anon
    Anon:
    Unless you can provide the original code, it's still easily possible it was originally in Java and this version has been ported to demonstrate the basic WTF (recursive iteration of the same call).
    It's also easily possible that it was written in an attic Greek derivitant of Whitespace but there's no valid reason to make that assumption. Since porting it would change the nature of the WTF and be unnecessary logic dictates it wasn't ported.
    Anon:
    In any case, it doesn't change the basic point: this was probably done to work around a race condition. It's still braindead, it's still stupid, it's still a WTF, but presumably the original was done in such a way that it involved a race condition. (Which actually casts doubt on the original being Java - Java's SimpleDateFormat would likely give you a wrong answer rather than throwing an exception.)

    And it's still a WTF that Java has managed to create a date parser/formatter that is not thread safe. It takes a special kind of developer to make non-reentrant methods in an immutable object.

    DateFormat is perfectly re-entrant, being thread safe is something different entirely and there's no reason for it to be thread safe and a good one for it not to.

  • Anon (unregistered) in reply to AnonCoder
    AnonCoder:
    It's also easily possible that it was written in an attic Greek derivitant of Whitespace but there's no valid reason to make that assumption. Since porting it would change the nature of the WTF and be unnecessary logic dictates it wasn't ported.
    Hasn't prevented them from porting in the past. In fact, most of the entries are "ported" from another language as part of the anonymization process.
    DateFormat is perfectly re-entrant, being thread safe is something different entirely and there's no reason for it to be thread safe and a good one for it not to.
    As it turns out, Java text formats aren't immutable. That's what make it non-thread-safe. You can change the pattern and various other items in it for no apparent reason.

    Turns out none of the Java formatting classes are thread safe. This is actually worse than it sounds because it means someone could change, say, the platform-specific, locale-specific date format. Who knows, maybe the various getInstance() methods don't return a singleton, because the Java documentation sure doesn't tell you.

    In any case, I think we can all agree that C# is infinitely superior to Java.

  • Anonymous (unregistered) in reply to Anon

    I have "inside information", this code snippet appears exactly as submitted, and it is definitely c#.

  • AnonCoder (unregistered) in reply to Anon
    Anon:
    Hasn't prevented them from porting in the past. In fact, most of the entries are "ported" from another language as part of the anonymization process.
    Really? Got any good examples?
    Anon:
    As it turns out, Java text formats aren't immutable. That's what make it non-thread-safe. You can change the pattern and various other items in it for no apparent reason.
    No apparent reason? Not apparent to you perhaps.

    Why shouldn't you change the properties of an object through it's public API?

    Anon:
    Turns out none of the Java formatting classes are thread safe. This is actually worse than it sounds because it means someone could change, say, the platform-specific, locale-specific date format. Who knows, maybe the various getInstance() methods don't return a singleton, because the Java documentation sure doesn't tell you.
    /boggle.

    If the factory methods returned a singleton the javadoc would say so. There are plenty of pointless, unnecessary things java classes also don't do that they don't tell you about. That approach to documenting seems to work fairly well, but I guess if you prefer to do it by ruling out every idiotic thing your code could do but doesn't that's fair enough.

    Why would I unnecessarily expose my instance of DateFormat so it could be manipulated by other threads? That would be utterly stupid.

    Interestingly the microsoft behaviour appears to be the same as near as I can make out - instances in the DateTime struct aren't thread safe.

    They provide threadsafe statics, which of course some developers will use in ignorance of the costs.

    Anon:
    In any case, I think we can all agree that C# is infinitely superior to Java.
    I couldn't say since fortunately I don't have to use it but I can assure you that the developers that do most obviously aren't.
  • Anon (unregistered) in reply to AnonCoder
    AnonCoder:
    Anon:
    As it turns out, Java text formats aren't immutable. That's what make it non-thread-safe. You can change the pattern and various other items in it for no apparent reason.
    No apparent reason? Not apparent to you perhaps.
    What's the most common use-case for formats? You create them once, and then reuse them to format or parse all the data you intend to format or parse with them.

    About the only time the format changes is when the user changes the format or if the format comes from another source. In any case, you might as well create a new one, since that's effectively what's happening internally anyway.

    As a good example of why you'd want to do it this way, take a look at the Java regex library. Pattern objects in Java are compiled once and then are immutable. A date format is simply a certain case of a pattern. Instead of being a generic pattern, it happens to specify a date, and can also be used to format dates.

    AnonCoder:
    /boggle.

    If the factory methods returned a singleton the javadoc would say so. There are plenty of pointless, unnecessary things java classes also don't do that they don't tell you about. That approach to documenting seems to work fairly well, but I guess if you prefer to do it by ruling out every idiotic thing your code could do but doesn't that's fair enough.

    Why would I unnecessarily expose my instance of DateFormat so it could be manipulated by other threads? That would be utterly stupid.

    Again, what is the most common use for the locale-specific formats? I would assume it would be to use them, not change them.

    But change them you can - the Javadoc actually explains that the returned results are SimpleDateFormats and that you can change their pattern (making requesting them entirely pointless). Why would you ever want a locale-specific date format to be mutable?

    Most of the mutable fields change how the parse performs. These should be parameters given to the parse method. They shouldn't be member variables.

    Seriously, the SimpleDateFormat class could be a front-page article, its design is so retarded.

    How do you specify the timezone to display a date in? Member variable, not a parameter to the format method.

    Apparently they expect people to reuse the object for new objects, allowing them to change the pattern the object represents directly. (Why would you ever want to do that versus just creating a new object? No idea, but you can! I guess it might save a few hundred bytes...)

    All the Java text formatting classes are like this. It makes them non-thread safe, and requires every thread that might access a format create a new one.

    It requires the continual reparsing of the locale-specific format every time it's requested, despite the fact that the locale-specific pattern is never going to change.

    Of course, in Java, you're allowed to change the OS name and the current newline at the command line. (Seriously. Try "-Dline.separator=WTF!" some time and see what happens. I don't know if they fixed this, but you used to be able to get the Windows LAF to work under Linux using "-Dos.name=Windows 95".)

  • OracleGuy (unregistered) in reply to sas
    sas:
    The Real WTF(tm) is that he used overloading when a default argument would have been sufficient.

    C# doesn't allow default arguments/parameters you have to use overloading.

    captcha: burned

  • VinNt (unregistered)

    The REAL WTF is that's it tried only 10 times, and what if all would failed? Or for example it would work too fast to receive different inputs for parse?

    Captcha = gotcha

  • M.G. (unregistered) in reply to random person
    random person:
    djork:
    This is ridiculous. Why would you hard-code a maximum of 10 tries into a wonderful method like this? It should really just take a positive integer and move it towards the base case of 0. That way you can specify 10 tries, or 100 tries!

    since it takes an int, it could be passed -90 for 100 tries...

    Well, that's simple. Do it like this:

    while (tries != 0) {
        .
        .
        .
        tries = tries - (tries/Math.abs(tries)));
    }
    

    That way it always counts toward zero...

    (My first intentional WTF...)

  • Top Cod3r (unregistered)

    If you are criticizing this code then maybe you just haven't had to develop mission-critical enterprise software. One thing you probably haven't considered is this code is probably multi-threaded and running on a multi-processor, multi-core system, so in that case you have to build in retry logic in order to avoid system deadlocks. If you're a junior coder then I guess you might not understand that.

    The system clock is a shared resource, and only one thread can access it at any given time, so you have to follow this retry design pattern unless you want to get random intermittent errors (or worse yet, your clients may get the errors).

  • M.G. (unregistered) in reply to Top Cod3r
    Top Cod3r:
    If you are criticizing this code then maybe you just haven't had to develop mission-critical enterprise software. One thing you probably haven't considered is this code is probably multi-threaded and running on a multi-processor, multi-core system, so in that case you have to build in retry logic in order to avoid system deadlocks. If you're a junior coder then I guess you might not understand that.

    The system clock is a shared resource, and only one thread can access it at any given time, so you have to follow this retry design pattern unless you want to get random intermittent errors (or worse yet, your clients may get the errors).

    I suspect you are trolling, but I'll bite:

    1. WTF does this code have to do with the system clock? It's parsing a string into a DateTime object. In fact, it tries eleven times to do this with the same string and the same DateTime class' static method.

    2. Even if your multithreading and multi-CPU scenario is correct (I admit it probably is) and the DateTime.parse() method involves a shared resource that can only be accessed by one thread at a time, there are other ways to wrap proper synchronization around it.

    BTW, the DateTime.parse() docs are here: http://msdn2.microsoft.com/en-us/library/1k1skd40.aspx

  • (cs) in reply to quephird
    quephird:
    If at first you don't succeed, try, try, try, try, try, try, try, try, try again.

    sings you can get it if you really want...

  • wtw (unregistered)

    I had to do this into a software once, when a third party software we were using didn't work all that well. Changing it was not an option, and it just had to be called in a loop, trying a few times. It always works when called twice (sometimes three times is needed), but very rarely when called once. It messes something up with its memory.

    Doesn't exactly apply to this piece of code, thought.

  • Atario (unregistered) in reply to Josh
    Josh:
    The real WTF is passing the same data to a function and expecting to get different results!
    My
    ShuffleCards(Deck)
    function begs to differ.
  • Drak (unregistered)

    Had to do this once too, but did it with a while. Seems the encoding fucntion we were using (3rd party) was not thread safe, but that wasn't documented anywhere.

  • (cs) in reply to Atario
    Atario:
    Josh:
    The real WTF is passing the same data to a function and expecting to get different results!
    My
    ShuffleCards(Deck)
    function begs to differ.

    Function != method, at least to some people.

  • Err... (unregistered) in reply to operagost
    operagost:
    In order to understand recursion, you must first understand recursion.
    Think... Think... Think... Think... Error: Stack Overflow.
  • gygax (unregistered) in reply to Someone You Know
    Someone You Know:
    Atario:
    Josh:
    The real WTF is passing the same data to a function and expecting to get different results!
    My
    ShuffleCards(Deck)
    function begs to differ.

    Function != method, at least to some people.

    Well, to make it a method, why not use deck.Shuffle()?

  • Diego (unregistered) in reply to WTFer
    WTFer:
    It just goes to show what equal opportunity laws and hiring the mentally handicapped get you

    captcha - xevious, damn that was a good video game

    that IS a good videogame :-)

    captcha - pinball, and these are fun too :) :) :) :) :)

  • (cs) in reply to AnonCoder
    AnonCoder:
    Anon:
    Unless you can provide the original code, it's still easily possible it was originally in Java and this version has been ported to demonstrate the basic WTF (recursive iteration of the same call).
    It's also easily possible that it was written in an attic Greek derivitant of Whitespace but there's no valid reason to make that assumption. Since porting it would change the nature of the WTF and be unnecessary logic dictates it wasn't ported.

    The simple explanation is that it was ported from Java to C# by someone (either someone actually porting the application it was a part of, or anonymization for this website) who didn't understand the Java issue it was working around, and thus didn't understand that changing it changed the nature of the story.

  • (cs)

    There seems to be a lot of comments stating that this is a common solution; some even admitting to having implemented that method to overcome various issues.

    I think that is a big WTF.

    I personally do not subscribe to the Quantum Theory of Applied Logic. I would never be satisfied with a solution such as this to solve a seemingly random and sporadic issue, nor should anybody be. Might as well believe that it was caused by solar flares, gamma rays, or by flushing the toilet, and accept that god will smite your application out of spite once in a while and you're just all doomed. Maybe he just didn't like that last comment you wrote.

    If in fact there is a multi-threading issue, there are proper ways to synchronize the calls and avoid collisions or race conditions, without having to resort to voodoo.

     -dZ.
    
  • (cs) in reply to Random832
    Random832:
    AnonCoder:
    Anon:
    Unless you can provide the original code, it's still easily possible it was originally in Java and this version has been ported to demonstrate the basic WTF (recursive iteration of the same call).
    It's also easily possible that it was written in an attic Greek derivitant of Whitespace but there's no valid reason to make that assumption. Since porting it would change the nature of the WTF and be unnecessary logic dictates it wasn't ported.

    The simple explanation is that it was ported from Java to C# by someone (either someone actually porting the application it was a part of, or anonymization for this website) who didn't understand the Java issue it was working around, and thus didn't understand that changing it changed the nature of the story.

    I would genuinely love to see an Attic Greek derivative of Whitespace -- the comments alone would make it worthwhile. (I still remember the sheer joy of watching Xena's "A day in the life," complete with Attic Greek storyboards.)

    Unfortunately, Attic Greek doesn't have tab characters. In fact, I'm not even sure that it has newline characters. (And if it did, then I'm sure the Attic Mac, the Attic *nix, and the Attic Windows -- you do have windows in your attic, don't you? -- versions would be incompatible.) I'm sure this would be an excellent candidate for the next OMGWTF contest, though.

    In the mean time, the code as presented makes no sense whatsoever. Obviously. Taking your "simple explanation" at face value, this would imply that the original Java is a worthwhile effort at "working around" a "Java issue." It isn't. It's dumb. If the issue exists, then you

    (a) use synchronisation (on the assumption that you have control over all programs affected by this "Java issue," which is quite possible) (b) complain like hell to Sun until they fix this ridiculous state of affairs (c) write your own goddamn formatting routine, conceivably using C and JNI.

    What you do not do is to hold your breath and count to ten.

    Your "simple explanation" fails in that (1) the result is still a WTF; (2) you are assuming that some fairly intelligent and competent person, somewhere along the way, has made a bonehead mistake; and (3) Occam's razor would suggest that the person who wrote the code in the first place is a total nitwit.

    Since (3) covers around 95% of programmers these days, I lean towards Occam's razor.

  • Nico (unregistered) in reply to DZ-Jay

    "I would never be satisfied with a solution such as this to solve a seemingly random and sporadic issue, nor should anybody be."

    I don't think that any body is, but fixing the library or framework you are using, while still having to do your actual work, might be a non-trivial task that takes a lot of time.

  • (cs) in reply to Nico

    "I don't think that any body is, but fixing the library or framework you are using, while still having to do your actual work, might be a non-trivial task that takes a lot of time."

    You don't have to fix "the library or framework" as you say. If you are resigned to working around the problem, why not work around it the right way. My guess is that it was already suspected that the issue lie with a race condition of some sort; there is just no other reason to try to fix a failed function call by calling it again. The developer was either lazy or dumb: either way a WTF.

    -dZ.

  • (cs) in reply to jimlangrunner
    jimlangrunner:
    How do you know that, like Schrödinger's cat, you didn't change the value just by observing it?
    Even Schrödinger's cat stays in its observed state after the box is opened. However many times you look at it.
  • (cs) in reply to Ancient_Hacker
    Ancient_Hacker:
    Way back, mean waaay back, computers were not so reliable. For instance the CDC 1604, at least the first few, were built using transistors that did not meet the tight specs for the Navy's Univac computers. So instead of paying $50 per transistor, the marginal ones went for pennies each. Seymour Cray designed the gates and flip-flops of the 1604 to tolerate, mostly, the wider tolerances for gain and leakage.

    But on hot days things could get close to the margins, so it was not unusual to have to write programs with built-in double-checking of results.

    Here's a source that claims it was the 1604's predecessor, the 12-bit CDC 160, but doesn't go into any more detail than that: http://www.cap-lore.com/Hardware/Inside.html

    I read somewhere (recently) that it was common to double-check the results of valve-based computers, simply because valves are notoriously difficult to predict even when they're working, the more so the older they were (not to mention the silly failure rate). But with the dawn of transistorised computers - especially junction transistors; point-contact ones were flakier - the practice died out, because transistors either worked as they were supposed to or didn't work at all. (Sorry, I have no idea where I read that, so I can't give a reference.)

  • (cs) in reply to gwenhwyfaer
    gwenhwyfaer:
    Ancient_Hacker:
    Way back, mean waaay back, computers were not so reliable. For instance the CDC 1604, at least the first few, were built using transistors that did not meet the tight specs for the Navy's Univac computers. So instead of paying $50 per transistor, the marginal ones went for pennies each. Seymour Cray designed the gates and flip-flops of the 1604 to tolerate, mostly, the wider tolerances for gain and leakage.

    But on hot days things could get close to the margins, so it was not unusual to have to write programs with built-in double-checking of results.

    Here's a source that claims it was the 1604's predecessor, the 12-bit CDC 160, but doesn't go into any more detail than that: http://www.cap-lore.com/Hardware/Inside.html

    I read somewhere (recently) that it was common to double-check the results of valve-based computers, simply because valves are notoriously difficult to predict even when they're working, the more so the older they were (not to mention the silly failure rate). But with the dawn of transistorised computers - especially junction transistors; point-contact ones were flakier - the practice died out, because transistors either worked as they were supposed to or didn't work at all. (Sorry, I have no idea where I read that, so I can't give a reference.)

    Still irrelevant.

    The code, as presented, is moronic.

    I find it hard to believe that any sane developer would look at it and not say:

    Worse Than Failure?

    ... or something like that.

  • (cs) in reply to real_aardvark
    real_aardvark:
    gwenhwyfaer:
    *snip interesting anecdotage*
    Still irrelevant.
    Yes, but I found the historical excursion interesting. I do apologise for indulging my own proclivities...
    The code, as presented, is moronic.
    ...when so many people are so desperate to state the bleeding obvious. Because silence is obviously assent.
  • (cs) in reply to operagost
    operagost:
    In order to understand recursion, you must first understand recursion.

    For a quick tutorial, click here.

  • prof_hobart (unregistered) in reply to Josh
    Josh:
    The real WTF is passing the same data to a function and expecting to get different results!
    Not necessarily. I've had at least one 3rd party library in the past where I've had no choice but to try multiple times (with exactly the same - correct - parameters), failing several times before finally working.
  • drew (unregistered) in reply to Josh

    I tihnk the definition of insanity is doing the same thing twice and expecting different results.

    This function seems to match.

  • (cs)

    TRWTFI: catch clause without Exception type specified. This is not only a sin, but also forces us to speculate about the nature of the problem instead of providing the reader with selfexplanatory code.

  • The danish guy (unregistered)

    Homer Simpson: Kids you tried your best and failed miserably - the lesson is: never try.

    I guess this is the opposite

Leave a comment on “Tenth Time's The Charm”

Log In or post as a guest

Replying to comment #:

« Return to Article