• (cs) in reply to remi bourgarel
    remi bourgarel:
    - idiot #4 we will guess it like this : if it starts with a 0 it's octal no one starts an int with 0 if it's not octal, right ?
    JavaScript is not the only place where this happens. I get two different results from these two commands.

    ping 10.2.1.52 ping 010.002.001.052

  • (cs) in reply to frits
    frits:
    An API method should require as close to one line of code with very few supplemental parameters as possible for routine tasks. One line of code with one parameter and one return value (when appropriate) is optimal. The further from this ideal the suckier the API is. In other words, don't make have to construct an API for your API.
    Fair enough; let me reword the question: How exactly does one go about objectively measuring "sucky-ness" with respect to a given API?

    Furthermore, is there a unit of measurement for how much something "sucks"? For example, could one say that JavaScript's Date API sucks at 1.21 giga-biebers?

  • BentFranklin (unregistered)

    Suckiness is measured in inches of mercury.

  • Fennec (unregistered) in reply to BentFranklin
    BentFranklin:
    Suckiness is measured in inches of mercury.

    My project's original (10 years ago) codename, and its namespace, is 'Mercury'.

    :S

  • North Shore Beach Bum (unregistered)

    TRWTF is that Dates in JavaScript were designed to be (real year - 1900). It was only later that methods were added to handle the year as is. As such, writing wrappers to the date library is not a WTF by itself.

  • (cs) in reply to ÃÆâ€â„
    ÃÆâ€â„:
    Alex forgot the part where the calendar ran out of wheels on December 23rd, 2012.
    I think you're supposed to set all the wheels back to their start positions...
  • (cs) in reply to BentFranklin
    BentFranklin:
    Suckiness is measured in inches of mercury.

    I thought it was in milli-Tory Blacks.

  • Huh? (unregistered) in reply to remi bourgarel
    remi bourgarel:
    JS is a big WTF and this is right to do some kind of a facade pattern

    parseInt for instance, I don't know how many stupid people you must have to get to this kind of mess :

    • Smart #1 hey we should do a function that parse a string and give you the int value
    • idiot #1 you're so right, but what if the guy want to parse a binary string ?
    • smart #1 no one do that
    • idiot #2 STFU you idiot ! we should add a parameter with the base
    • idiot #3 Yes , and if the user doesn't send this parameter we should guess on wich base
    • idiot #4 we will guess it like this : if it starts with a 0 it's octal no one starts an int with 0 if it's not octal, right ?
    • all the idiot around : Yes off course !
    And so they chose to mimic the C compiler.
  • Mike (unregistered) in reply to Stephen Cleary
    Stephen Cleary:
    Jon Skeet is a Google employee who works in Java in his day job and is recognized as one of the top C# experts at night. He is porting Joda Time from Java to C#, and blogging about his experiences: http://noda-time.blogspot.com/

    Interesting. I don't understand why you would write a second library for dates and times for Java. Jon's writeup about his design sounds to me exactly like how I use Date and Calendar objects in Java.

    Date objects are good for marking the instants in time he describes, with long milliseconds being useful for performing durations. It would be nice if you could add or subtract milliseconds from a Java Date, but it's easy enough to just use get/modify/set. Not ideal, but the resulting code is generally easy enough to understand.

    When it comes time to think in terms of human terms like months, days, hours, etc., you use Java Calendar objects. You manipulate these human-understood objects, and there are easy-to-use converters between Date objects and Calendar objects. Again, the API isn't perfect, with constants to indicate field selection, but the resulting code is generally easy to understand.

    I find the main reason people run into problems with dates and times in Java is when they use the wrong object for the job. This is usually because they either aren't aware of how best to use Date and Calendar objects, or because they are just not terribly good at thinking through clean solutions to programming problems. I have yet to see a time or date problem that could not be solved fairly elegantly using these two classes.

    Now, once you start interacting with database timestamps from Java, that's another story entirely. :-)

  • Huh? (unregistered) in reply to joeyadams
    joeyadams:
    Seeing as how C's most common application is writing C compilers, it logically follows that JavaScript's most common application is writing JavaScript compilers.
    Don't feed the troll, people.
  • Bael (unregistered) in reply to havokk

    How'd you guess my IP Address???

    Seriously though, that is pretty weird. Especially when you consider that 10.0.1.52 is a valid IP Address.

  • (cs)

    Fortunately the designers of JSON (JavaScript Object Notation) did something right. They decreed that a number can start with "0" only if "0" is the only digit to the left of the decimal point (or if no decimal point, the only digit). You cannot write a number in octal, and you cannot write a number that JavaScript would interpret as octal.

  • My Name (unregistered) in reply to Mike
    Mike:
    Stephen Cleary:
    Jon Skeet is a Google employee who works in Java in his day job and is recognized as one of the top C# experts at night. He is porting Joda Time from Java to C#, and blogging about his experiences: http://noda-time.blogspot.com/

    Interesting. I don't understand why you would write a second library for dates and times for Java. Jon's writeup about his design sounds to me exactly like how I use Date and Calendar objects in Java.

    [snip]

    I sure hope you code more cautious than you read.

  • nick (unregistered)

    That ParseInt replacement isn't the worst I've seen... http://support.microsoft.com/kb/191434

  • lomendil (unregistered) in reply to Bael
    Bael:
    Seriously though, that is pretty weird. Especially when you consider that 10.0.1.52 is a valid IP Address.

    That's an octal 0, of course!

  • Steve Allen (unregistered) in reply to Stephen Cleary

    The problem of counting seconds has its origin in the chaotic legal situation between any one country and any other. See http://www.ucolick.org/~sla/leapsecs/epochtime.html for the sad story. It's important to be sure what standard is being followed, or not, by all the hardware and software.

  • (cs) in reply to Anonymous
    Anonymous:
    Rajendra Kumar:
    How to add functionality of other calendars to this wonderful code? I have requirements for Persian, Ethiopic, and Saka calenders. Also, I neeed the UI code for this, code you pls advise?!

    Thx pls URGENT!!!

    Rajendra, I just love your occasional but hilarious posts. I'd really like to see the app you're building with all the teh codes that you people pls send you. Can you pls send me teh codes when it's finished?!
    It's about time we had another OMGWTF contest!

  • Richard (unregistered) in reply to remi bourgarel

    Regrettably, the insanity of treating leading zeros as Octal infects the core C-library, and everything that depends on atoi(). This includes PHP, C, Javascript, and plenty of other cases.

    Starting with "0b" for binary and "0x" for hex is perfectly sane, but the idea of leading 0 for octal is lunatic. Why not "0o" if we must. Nobody ever deliberately uses this mis-feature, but it catches the unwary so often.

  • Simon (unregistered) in reply to SCSimmons
    SCSimmons:
    *This would have been much easier to do if the rm command had a -stupidcode switch. Come to think of it, somebody should write that ...

    GNU 'find' can probably handle it. Try something like "find -stupidcode -delete", and let us know if it works.

  • Norman Diamond (unregistered)

    "Starting with "0b" for binary and "0x" for hex is perfectly sane, but the idea of leading 0 for octal is lunatic. Why not "0o" if we must. Nobody ever deliberately uses this mis-feature, but it catches the unwary so often."

    The historical reason was that C had a leading 0 for octal and everything else was decimal. 0x was invented later. Hexadecimal was already in use on mainframes but the inventors of C didn't predict that minis would evolve to the stage where hex would be convenient.

    Microsoft uses 0o for octal in resource files.

    Elsewhere, it would be nice if Microsoft used this wrapper for parseInt because they sure need it. In a country where it is conventional to input two-digit numbers for months, Microsoft's scripting blew up on 08.

  • David Cameron (unregistered)

    That r_parseInt() function is not a bad piece of code. The reality is that you rarely if ever want to parse an int that is not base 10, however if you have a string starting with a 0 this will be parsed as octal.

    I'd argue that is a completely reasonable piece of code that resolves a bug in javascript.

  • David Cameron (unregistered) in reply to Huh?
    Huh?:
    remi bourgarel:
    JS is a big WTF and this is right to do some kind of a facade pattern

    parseInt for instance, I don't know how many stupid people you must have to get to this kind of mess :

    • Smart #1 hey we should do a function that parse a string and give you the int value
    • idiot #1 you're so right, but what if the guy want to parse a binary string ?
    • smart #1 no one do that
    • idiot #2 STFU you idiot ! we should add a parameter with the base
    • idiot #3 Yes , and if the user doesn't send this parameter we should guess on wich base
    • idiot #4 we will guess it like this : if it starts with a 0 it's octal no one starts an int with 0 if it's not octal, right ?
    • all the idiot around : Yes off course !
    And so they chose to mimic the C compiler.

    Supporting octal in this way makes sense in C. It makes no sense in Javascript.

    Idiots might be too mild a term.

  • Simon (unregistered) in reply to David Cameron
    David Cameron:
    Supporting octal in this way makes sense in C.

    Not really. Perhaps in certain niche uses it makes sense, but I've never intentionally used octal constants in 15-odd years of C coding.

  • (cs) in reply to boog
    boog:
    However, if I may be serious for a moment, I'd like to point out that the following comment he made deserves more attention than it's getting:
    I'm pretty sure that's true of all the comments I make ;)

    Also, following the previous comments, I'm pretty sure the Mercury (Quality Center) is the standard by which all suckyness relates. So on a scale of 1-10, MQC would be a 10, as well as anything Peoplesoft and lots of Oracle.

    As for Date APIs, I'm curious as to specific problems people have with them.

  • (cs) in reply to Dom
    Dom:
    What's the fuss with that parseInt() replacement? The default implementation tries to guess the base - and ends up with treating numbers as octals occasionally.

    Given that 99.98% of all users would type a base 10 number into the computer. (Yes, I made up the percentage. So?) It's only wonks like us that think in terms of octal.

    "Let's see here. Mr. Average Joe entered 170 into the field and so that would be $120, right?"

    I am reminded of a long-ago program that told me (paraphrased):

    "The trivial operation you want to perform on this disk is not supported on this disk type. Therefore I will assume you meant to perform the most time-consuming operation; the one that will lock all the users out and leave the entire system unusable for the next 45 minutes."

    When designing things (such as, for example, parseint) the default behaviors should always be the thing most commonly required and/or that which is least likely to be the wrong thing.

  • Sutherlands (unregistered) in reply to Coyne
    Coyne:
    When designing things (such as, for example, parseint) the default behaviors should always be the thing most commonly required and/or that which is least likely to be the wrong thing.
    As a C# dev, I can say that the compiler should never guess what you want.
  • Simon (unregistered) in reply to Sutherlands
    Sutherlands:
    Coyne:
    When designing things (such as, for example, parseint) the default behaviors should always be the thing most commonly required and/or that which is least likely to be the wrong thing.
    As a C# dev, I can say that the compiler should never guess what you want.

    Agreed - if in any doubt, abort, and let the user know there's a problem. By all means provide suggestions as to what you think they might have intended, but never try to guess.

  • (cs) in reply to frits

    An API should be as close as possible to the thinking of the programmer. If you have to translate what you think into what the computer thinks, it sucks. But sometimes the human thinking is wrong. Humans understand timezones but not datezones.

    Humans have been numbering months 1-12 for two thousand years; any API that numbers months 0-11 sucks.

  • Simon (unregistered) in reply to AndyCanfield
    AndyCanfield:
    Humans have been numbering months 1-12 for two thousand years; any API that numbers months 0-11 sucks.

    Oh yeah, that's always a favorite - both Java and Javascript annoy me with that behaviour. Although no less annoying is that the java.util.Date class uses years offset from 1900, so if you ask it for the current year, you get 110.

    I can live with that kind of crap from fossils like COBOL, but Java's not so old as to excuse Y2K braindeadedness like that. Yeah, I know the method's been deprecated since 1.1, but that just proves the point - it was just as stupid fifteen years ago, as it is today.

  • Bob (unregistered)

    What about Sep 1752?

  • Kael (unregistered)

    My favorite part is how you can call spin(32) to redefine a month as infinitely long.

  • Nagg0r (unregistered)

    Sorry for nagging, but attaching a logger does neither prove nor verify but only validate that it isn't skipping a day. :)

  • Anonymous (unregistered) in reply to David Cameron
    David Cameron:
    I'd argue that is a completely reasonable piece of code that resolves a bug in javascript.
    It's not a bug if it's by design. It works exactly as designed and exactly as intended; being stupid doesn't make it a bug.
  • Anonymous (unregistered) in reply to Sutherlands
    Sutherlands:
    Coyne:
    When designing things (such as, for example, parseint) the default behaviors should always be the thing most commonly required and/or that which is least likely to be the wrong thing.
    As a C# dev, I can say that the compiler should never guess what you want.
    As another C# dev, I agree with you completely. The single worst thing about C# compared to Java is the wholesale shift in mindset of the people writing the language. The Java mantra is "what you see is what you get". The C# mantra is "stuff as much compiler guesswork and syntactic sugar in there as possible, so what you see is only a tiny part of what you actually get".
  • Anonymous (unregistered) in reply to AndyCanfield
    AndyCanfield:
    Humans have been numbering months 1-12 for two thousand years; any API that numbers months 0-11 sucks.
    I kind of agree but at the same time I hate inconsistent indexer bases. Either index from 0 or index from 1, don't make me guess based on the type of collection I'm working with. If all the collections in the framework are zero indexed then I don't feel it is appropriate to make an exception for this one "special" collection type simply because the human brain finds it more asthetically pleasing.
  • cappeca (unregistered)

    I don't understand people that actually go and implement mechanical processes in programming. I've had a pretty bad discussion with a lot of people in a game forum once over a poker engine, where they would shuffle an array of 52 elements to distribute hands, while I just picked up a random number out of 13 and another out of 4 for each card. To them, apparently my argument that random should be random was flawed.

  • Wessleyd (unregistered) in reply to cappeca
    cappeca:
    while I just picked up a random number out of 13 and another out of 4 for each card.

    Great, two Ace of Spades in my hand then! (Or did you check against old occurences and tried and retried and retried until a solution was found?)

  • (cs) in reply to havokk

    This was an undocumented (as far as I could see) "feature" in TCP/IP for Windows 3.1 / MSDOS 5 and possibly earlier. When reading it's configuration text file, the MS TCP/IP stack would silently interpret IP address octets starting with 0 as octal (even if they had an 8 or a 9 - 018 was read as 16 and 019 as 17). I'm surprised (well, not really) that it has survived 'til now.

    I remember literally weeks and weeks of troubleshooting seemingly random disconnections from our newly migrated (from NetBEUI) TCP/IP network, until it finally clicked.

    This was before there was a standard easily available DHCP server for Windows, so we had hundreds of PCs with static IP addresses, of which some (about 20%) had leading 0's in their IP addresses (depending on whether one particular staff member had done the initial configuration). When two PCs had a duplicate IP address, the second workstation to be started in the morning would knock the first one off the network. So the first user would reboot, and when they reconnected it would knock the second PC off the network, which would then be rebooted and knock the first PC off again, and so on ad infinitum. This was before the days of any obvious error messages, so all the user would know was that their PC had been disconnected again and they had to reboot again. Because the IP addresses were "obviously" not the same, no-one ever suspected duplicate addresses. The way that non-octal digits were acceptable also helped to mask the problem.

  • by (unregistered) in reply to Anonymous
    Anonymous:
    Sutherlands:
    Coyne:
    When designing things (such as, for example, parseint) the default behaviors should always be the thing most commonly required and/or that which is least likely to be the wrong thing.
    As a C# dev, I can say that the compiler should never guess what you want.
    As another C# dev, I agree with you completely. The single worst thing about C# compared to Java is the wholesale shift in mindset of the people writing the language. The Java mantra is "what you see is what you get". The C# mantra is "stuff as much compiler guesswork and syntactic sugar in there as possible, so what you see is only a tiny part of what you actually get".

    Which C# are you using? The one written and maintained by MS, because as far as I know it's not a dynamic language (yes, I know 4.0 and DLR, etc.).

    The compiler will let you know if you've done something stupid, and as far as syntactic sugar goes: what do you mean? Lambdas, anonymous types, LINQ (deferred execution), etc.? Learn to use and embrace them; don't hate what you don't understand. There is no magic, everything is in the documentation.

    You would have to do something out-of-the-way kind of stupid to sneak a WTF past the compiler (like explicit casts, or using strings for everything, or just a bad design).

    Please be specific, and don't just throw out weak and ridiculous accusations.

  • Sanity (unregistered) in reply to Ale
    Ale:
    A Date API that sucks. Well, every Date API known do man sucks. Please, prove me wrong.

    I think I've seen a few that rock, but that's a matter of opinion.

    But this isn't about the API so much as the implementation. Whether or not the API sucks, a set implementation which takes O(n) time to add or remove items does, in fact, suck more than one which takes O(1).

  • Anonymous (unregistered) in reply to by
    by:
    Anonymous:
    Sutherlands:
    Coyne:
    When designing things (such as, for example, parseint) the default behaviors should always be the thing most commonly required and/or that which is least likely to be the wrong thing.
    As a C# dev, I can say that the compiler should never guess what you want.
    As another C# dev, I agree with you completely. The single worst thing about C# compared to Java is the wholesale shift in mindset of the people writing the language. The Java mantra is "what you see is what you get". The C# mantra is "stuff as much compiler guesswork and syntactic sugar in there as possible, so what you see is only a tiny part of what you actually get".

    Which C# are you using? The one written and maintained by MS, because as far as I know it's not a dynamic language (yes, I know 4.0 and DLR, etc.).

    The compiler will let you know if you've done something stupid, and as far as syntactic sugar goes: what do you mean? Lambdas, anonymous types, LINQ (deferred execution), etc.? Learn to use and embrace them; don't hate what you don't understand. There is no magic, everything is in the documentation.

    You would have to do something out-of-the-way kind of stupid to sneak a WTF past the compiler (like explicit casts, or using strings for everything, or just a bad design).

    Please be specific, and don't just throw out weak and ridiculous accusations.

    OK, you asked so here's a random example for you. I had to write a new component from the ground up, a fairly trivial database application, so I used the opportunity to get my hands dirty with LINQ to SQL. At first I really enjoyed the ease of lambda expressions and fluidity of the syntax. Right up until I needed to do something that simply couldn't be expressed in lambda statements. Believe it or not, it is pretty easy to reach this point with even trivial querying requirements.

    To cut a long story short, I needed to build up a query sequentially based on a set of given filter criteria. I needed the underlying SQL to comprise of the logic ((A and B) or (C and D)). That is not a complicated query by any stretch of the imagination but it is physically impossible to express with lambda statements. Of course, lambda statements are just syntactic sugar for the Expression<Func<T, bool>> class. In order to get the logic I needed, I had to create instances of these classes then manually manipulate them with functions such as the following:

    private Expression<Func<T, bool>> LambdaAnd<T>(Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
    {
        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
        return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
    }
    
    private Expression<Func<T, bool>> LambdaOr<T>(Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
    {
        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
        return Expression.Lambda<Func<T, bool>>(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
    }
    
    I had to learn about the underlying classes and it's pretty obvious that code such as that above is a lot more complicated than lambda statements. But hell, it ain't rocket science and I learnt very quickly that you can do so much more if you understand and use the underlying classes directly.

    For some reason, Microsoft would prefer you to use some watered down syntactic sugar that barely even scrapes the surface of what is possible. They hide and abstract the real classes, dumbing down the code and taking a huge amount of power out of the hands of the developer.

    I'm a smart guy who can handle these concepts perfectly well without needing them dumbed down and presented behind a layer of syntactic sugar that robs me of the ability to solve complex problems. Maybe you're different, I don't know, but I for one do not want this; I want to work with real classes and actually understand how they work, instead of just cargo-culting it with silly syntax tricks.

    Is that specific enough for you?

  • Jeff Grigg (unregistered) in reply to frits?
    frits?:
    Seriously? Who hasn't done something like this?
    I've done this in JUnit code, to test "Julian" date functions, because it's easy to show that it's correct. But I've never done this in production code, and I hope I never will.
  • (cs) in reply to Anonymous
    Anonymous:
    I needed the underlying SQL to comprise of the logic ((A and B) or (C and D)). That is not a complicated query by any stretch of the imagination but it is physically impossible to express with lambda statements. [...] Is that specific enough for you?
    No, because
    IEnumerable<Tuple<bool, bool, bool, bool>> list = new List<Tuple<bool, bool, bool, bool>>
                 {new Tuple<bool, bool, bool, bool>(false, false, true, true)};
    foreach(var newVal in list.Where(val => (val.Item1 && val.Item2) || (val.Item3 && val.Item4)))
    {
      //Breakpoint reached
    }
    

    I must be missing something important.

  • Anonymous (unregistered) in reply to Sutherlands
    Sutherlands:
    Anonymous:
    I needed the underlying SQL to comprise of the logic ((A and B) or (C and D)). That is not a complicated query by any stretch of the imagination but it is physically impossible to express with lambda statements. [...] Is that specific enough for you?
    No, because
    IEnumerable<Tuple<bool, bool, bool, bool>> list = new List<Tuple<bool, bool, bool, bool>>
                 {new Tuple<bool, bool, bool, bool>(false, false, true, true)};
    foreach(var newVal in list.Where(val => (val.Item1 && val.Item2) || (val.Item3 && val.Item4)))
    {
      //Breakpoint reached
    }
    

    I must be missing something important.

    You are missing something important (the keywords you missed were "build up a query sequentially") but I'm just about to go home (UK here) so bear with me and I'll follow up tomorrow. And just FYI, that code is absolutely horrible. I would much rather use the underlying classes directly, I consider it to be far more readable than that utter mess you've concocted with lambdas. But hey, it's a completely moot point because that abomination won't actually work in my scenario. Have a good evening, check back tomorrow.

  • (cs) in reply to Simon
    Simon:
    Sutherlands:
    Coyne:
    When designing things (such as, for example, parseint) the default behaviors should always be the thing most commonly required and/or that which is least likely to be the wrong thing.
    As a C# dev, I can say that the compiler should never guess what you want.

    Agreed - if in any doubt, abort, and let the user know there's a problem. By all means provide suggestions as to what you think they might have intended, but never try to guess.

    I agree with that as well. "Guessing" is bad, because it means that there are criteria the compiler uses to go this way vs. that way that may not be clear. The "parseint" problem is a perfect example.

    There's nothing wrong with defaults, though, so long as they are always predicatable; even if they are wrong (though wrong can be annoying). In the case of "parseint" again, there is nothing wrong with it assuming a default of base 10, so long as it always assumes that.

    (It would be okay if it defaulted octal. That might be annoying, because you have to supply the 10 every time, but at least you know how it's going to behave if you omit the 10.)

    What caused the problem with it was its semi-unpredicatable guessing: "Well, I think this looks octal, so we'll do that;" vs "This isn't octal so it must be base 10." That type of nonsense is an invitation to program faults.

  • Design Pattern (unregistered) in reply to by
    by:
    Which C# are you using?
    Probably that in which something as innocently looking like assigning a value to a field can lead to event propagation in the background.

    Or even popping up an exception from the database telling you it doesn't like the value, if the programmer of the class thought that hidden persistence is a good idea.

    CAPTCHA: persto = persist in octal

  • (cs) in reply to Anonymous
    Anonymous:
    And just FYI, that code is absolutely horrible. I would much rather use the underlying classes directly, I consider it to be far more readable than that utter mess you've concocted with lambdas. But hey, it's a completely moot point because that abomination won't actually work in my scenario. Have a good evening, check back tomorrow.
    Which part is horrible? The part I created just to test that you can do that code, or... no I guess that was the only part I did. :roll:

    Addendum (2010-12-07 15:33): Since you decided that "using the underlying classes" is important, I'll add this so that you don't focus on that, and instead actually show what the problem is:

    List aList = new List { new A { IsActive = false }, new A { IsActive = true } };
    List bList = new List { new B { IsInactive = false}, new B { IsInactive = true } };
    List<C> cList = new List<C> { new C { IsAwesome = true }, new C { IsAwesome = true } };
    List<D> dList = new List<D> { new D { IsInawesome = true }, new D { IsInawesome = true } };
    
    var enumerable =
      from a in aList
      from b in bList
      from c in cList
      from d in dList
      where (a.IsActive && b.IsInactive) || (c.IsAwesome && d.IsInawesome)
      select new Tuple<A, B, C, D>(a, b, c, d);
  • Simon (unregistered) in reply to Anonymous
    Anonymous:
    I kind of agree but at the same time I hate inconsistent indexer bases. Either index from 0 or index from 1, don't make me guess based on the type of collection I'm working with. If all the collections in the framework are zero indexed then I don't feel it is appropriate to make an exception for this one "special" collection type simply because the human brain finds it more asthetically pleasing.

    And yet while some APIs use 0-based months in complete inconsistency with human expectation, I'm not aware of a single one that takes the obvious next step of using 0-based days. Because having 7 be the 8th of the month would just be confusing - yet having 11 be the 12th month is fine?

  • Anonymous (unregistered) in reply to Anonymous
    Anonymous:
    Sutherlands:
    Anonymous:
    I needed the underlying SQL to comprise of the logic ((A and B) or (C and D)). That is not a complicated query by any stretch of the imagination but it is physically impossible to express with lambda statements. [...] Is that specific enough for you?
    No, because
    IEnumerable<Tuple<bool, bool, bool, bool>> list = new List<Tuple<bool, bool, bool, bool>>
                 {new Tuple<bool, bool, bool, bool>(false, false, true, true)};
    foreach(var newVal in list.Where(val => (val.Item1 && val.Item2) || (val.Item3 && val.Item4)))
    {
      //Breakpoint reached
    }
    

    I must be missing something important.

    You are missing something important (the keywords you missed were "build up a query sequentially") but I'm just about to go home (UK here) so bear with me and I'll follow up tomorrow.

    [OK, forget about this bit, I concede I didn't read it properly and didn't realise you were just setting up some test data. I apologise, so let's not get off-topic]

    But hey, it's a completely moot point because that abomination won't actually work in my scenario. Have a good evening, check back tomorrow.

    OK, I'm back! My siginificant other has abandoned me in favour of her sewing machine so I've had some time to write up an example scenario for you (in my spare time, aren't I nice?!). I'm very much looking forward to you proving me wrong about lambdas because I'd love to clean up my code.

    You said you must be missing something important and you were. I specifically said I needed to build up a query sequentially, although maybe I should have said dynamically. Anyway, the point is that you don't always have all your filter criteria up-front to build a single lambda statement with. Very often you need to build up a statement piecemeal based on various conditional logic. This is where lambdas fall down, because using the syntactic sugar only lets you build statements in one hit, there is no good way to progressively build up a statement as you go.

    So I've produced a dramatically simplified example for you based loosely on my scenario. The table you are querying with LINQ to SQL consists of 4 columns; SourceId, SourceName, TargetId and TargetName. Your query method accepts a criteria object that has properties matching the columns, so we have Criteria.SourceId, Criteria.SourceName, Criteria.TargetId and Criteria.TargetName. Any of these may be null but any that are provided should be used to filter on the appropriate column. The critieria object contains an addtional property - Criteria.TwoWaySource. If this is true, you need to return all the rows where the source criteria values appear in either the source columns or the target columns. In other words, you need to return all the rows where ((SourceId = Critieria.SourceId [AND SourceName = Criteria.SourceName]) OR (TargetId = Criteria.SourceId [AND TargetName = Criteria.SourceName])). The bits in angle brackets are just there to indicate that you may have to additionally filter on these properties if they are provided, but as I already said, any of these properties could be null in which case that property should be ignored.

    Please satisfy these requirements using lambda expressions. Don't even think of resorting to a separate "if" statement for every single possible combination of criteria states because in the real thing there are way more values than this so an if statement to cover every single permutation is totally unrealisitic, it would span thousands of lines and be completely unmaintainable. You're going to have to query each property and dynamically build up your statement so that any possible permutation generates the right SQL. This is just some pseudocode to give you an idea:

    if (Criteria.SourceId != null)
    {
      // SQL needs to be SELECT * FROM table WHERE SourceId = Criteria.SourceId.
      // Easy with a lambda: t => t.SourceId == Criteria.SourceId
    }
    
    if (Criteria.SourceName != null)
    {
      // SQL now needs to be whatever we previously defined but with the addition of
      // of AND SourceName = Critieria.SourceName. We need to take the existing query
      // (if any) and AND it with a new query but this is not possible with lambdas.
    }
    
    // So on for TargetId and TargetName as necessary
    
    if (Criteria.TwoWaySource)
    {
      // Oh shit, source values are two way! Now we need to take the existing query, 
      // whatever the hell that is, and include OR TargetId = Criteria.SourceId,   
      // which may also need to be ANDed with TargetName = Criteria.SourceName. 
      // This can't be done with lambdas either!
    }

    Well, I've given you more than enough information on the requirements, let's see you achieve this using nothing but lambda expressions.

  • Anonymous (unregistered) in reply to Simon
    Simon:
    Anonymous:
    I kind of agree but at the same time I hate inconsistent indexer bases. Either index from 0 or index from 1, don't make me guess based on the type of collection I'm working with. If all the collections in the framework are zero indexed then I don't feel it is appropriate to make an exception for this one "special" collection type simply because the human brain finds it more asthetically pleasing.

    And yet while some APIs use 0-based months in complete inconsistency with human expectation, I'm not aware of a single one that takes the obvious next step of using 0-based days. Because having 7 be the 8th of the month would just be confusing - yet having 11 be the 12th month is fine?

    This doesn't change my opinion at all. I want consistent indexed collection bases, end of story.

Leave a comment on “Confessions: rachetingDateObject”

Log In or post as a guest

Replying to comment #:

« Return to Article