• Anon (unregistered)

    It's not just "not exactly now". Imagine running the script just before the end of the hour, the hour may be '17' and minute '59', and on the next operation, the hour may be '18' and the minutes '0'. It'll be an hour off. At the end of the day, it may be a whole day off. Or a whole month. Or even a whole year.

    That should be fun to debug!

  • Anon (unregistered) in reply to Anon
    Anon:
    It's not just "not exactly now". Imagine running the script just before the end of the hour, the hour may be '17' and minute '59', and on the next operation, the hour may be '18' and the minutes '0'. It'll be an hour off. At the end of the day, it may be a whole day off. Or a whole month. Or even a whole year.

    That should be fun to debug!

    Can't see how you came to that conclusion. I see how each parameter would get parsed in turn (left-to-right in C#?), but even so it just means time would move on a fraction of a second as each parameter gets processed. The end result would may have switched on to a new second, hour, month etc, but the difference between 'now' and the final result would only be the sum of each fraction of a second it takes to process each parameter. Unless I'm missing something :)

  • Hasse de great (unregistered)

    20131231235959.99999... + 0.00...1 --> 20130101000000.00000... is (almost) one year off

  • Jim (unregistered)

    10.. 9... 8... 7... 6... 5... 4... 3... 2... 1...

    Happy new, er, wait, last year!

  • Walky_one (unregistered) in reply to Anon
    Anon:
    Can't see how you came to that conclusion. I see how each parameter would get parsed in turn (left-to-right in C#?), but even so it just means time would move on a fraction of a second as each parameter gets processed. The end result would may have switched on to a new second, hour, month etc, but the difference between 'now' and the final result would only be the sum of each fraction of a second it takes to process each parameter. Unless I'm missing something :)
    Yes. You do miss something:

    Now.Hour -> 17:59:59 -> returns 17 now.Minute -> 18:00:00 -> returns 0

    So now we will build a date time for 17:00 (which definitely is NOT close to 17:59 or 18:00

    And it also works the other way around (e.g. if minute is done before hour. You just will be one hour late --> 18:59)

  • MP (unregistered) in reply to Anon

    Consider the time is '2014-12-31 23:59:59' when your method begins.

    If the time happens to tick over to '2015-01-01 00:00:00' just after you read the year part, then your full timestamp will be '2014-01-01 00:00:00' - an entire year out.

  • Anon (unregistered) in reply to MP
    MP:
    Consider the time is '2014-12-31 23:59:59' when your method begins.

    If the time happens to tick over to '2015-01-01 00:00:00' just after you read the year part, then your full timestamp will be '2014-01-01 00:00:00' - an entire year out.

    Thank you for all the people who corrected my flaky conclusion!

  • Walky_one (unregistered)

    And as a little side effect you can even get nice stuff like 31 of february if you time it right.

    Not sure how the DateTime constructor reacts to these parameters. Chances for an error are pretty high though...

  • Tom (unregistered)

    The last one is not that much of a WTF... None of the suggested existing types provide the same behavior.

    • Tuples don't override the equality and inequality operator, and since it's a class, these operators perform a reference equality
    • KeyValuePair doesn't override them either, and since it's a struct, there is no default implementation

    On the other hand, it is a mild WTF for these reasons:

    • The overriding of Equals and GetHashCode is redundant: for value types, the default implementation of these methods already take each field into account
    • public fields are bad; public mutable fields are very bad; public mutable fields in a struct should be a firing offense.
  • WTF (unregistered)
    return (Key.GetHashCode() + Value.GetHashCode());
    This will not provide the wanted behavior since 1 + 2 == 2 + 1 whilst a StringString with key 1 and value 2 should not be equal to a StringString with key 2 and a value of 1 according to the equality override.
  • DamienK (cs) in reply to WTF
    WTF:
    return (Key.GetHashCode() + Value.GetHashCode());
    This will not provide the wanted behavior since 1 + 2 == 2 + 1 whilst a StringString with key 1 and value 2 should not be equal to a StringString with key 2 and a value of 1 according to the equality override.

    You're obviously not that familiar with the requirements for a hash code. Two objects of the same type returning the same hash code might be equal. If you have such a situation, then you have to check for actual equality using Equals.

    GetHashCode returns an int, but there are more than 2^32 possible combinations of two strings (heck, there are more than 2^32 individual strings) and so you will have hash collisions anyway.

  • Palad1 (unregistered)

    The StringString struct is fine. Tuple is a class, and KeyValuePair<T,U> doesn't implement IEquatable<KeyValuePair<T,U>>.

    The only thing missing from StringString is declaring the implementation of IEquatable<stringstring>, and the fact that key and value are not readonly.<p> </stringstring>

  • kilroo (cs) in reply to Walky_one
    Walky_one:
    And as a little side effect you can even get nice stuff like 31 of february if you time it right.

    You're getting the month before the day.

  • Omni (unregistered)

    Can't help but think of MoonMoon when reading that last snippet eheh

    captcha: letatio - things you do to a lamp

  • anonymous (unregistered)

    I feel like the compiler should be smart enough to know that a dozen different copies of Now.DateTime that aren't used more than once and have no explicit delay between their invocation should really all be the same DateTime object.

  • Scourge of programmers. (unregistered)

    I believe the objective here is make the code unmanageable for the next programmer who steps in.

    Have you not seen Kitchen Casino?

  • Anonymous (unregistered)

    If you're interested, here's the IL code generated with LINQPad 4, with optimization on:

    IL_0000:  ldloca.s    00 // StartTime
    IL_0002:  call        System.DateTime.get_Now
    IL_0007:  stloc.1     // CS$0$0000
    IL_0008:  ldloca.s    01 // CS$0$0000
    IL_000A:  call        System.DateTime.get_Year
    IL_000F:  call        System.DateTime.get_Now
    IL_0014:  stloc.2     // CS$0$0001
    IL_0015:  ldloca.s    02 // CS$0$0001
    IL_0017:  call        System.DateTime.get_Month
    IL_001C:  call        System.DateTime.get_Now
    IL_0021:  stloc.3     // CS$0$0002
    IL_0022:  ldloca.s    03 // CS$0$0002
    IL_0024:  call        System.DateTime.get_Day
    IL_0029:  call        System.DateTime.get_Now
    IL_002E:  stloc.s     04 // CS$0$0003
    IL_0030:  ldloca.s    04 // CS$0$0003
    IL_0032:  call        System.DateTime.get_Hour
    IL_0037:  call        System.DateTime.get_Now
    IL_003C:  stloc.s     05 // CS$0$0004
    IL_003E:  ldloca.s    05 // CS$0$0004
    IL_0040:  call        System.DateTime.get_Minute
    IL_0045:  call        System.DateTime.get_Now
    IL_004A:  stloc.s     06 // CS$0$0005
    IL_004C:  ldloca.s    06 // CS$0$0005
    IL_004E:  call        System.DateTime.get_Second
    IL_0053:  call        System.DateTime.get_Now
    IL_0058:  stloc.s     07 // CS$0$0006
    IL_005A:  ldloca.s    07 // CS$0$0006
    IL_005C:  call        System.DateTime.get_Millisecond
    IL_0061:  call        System.DateTime..ctor
    

    See, the compiler doesn't optimize the code. Not sure if the JIT does that, but probably not since DateTime.get_Now is not a pure function

  • Black Bart (unregistered) in reply to anonymous
    anonymous:
    I feel like the compiler should be smart enough to know that a dozen different copies of Now.DateTime that aren't used more than once and have no explicit delay between their invocation should really all be the same DateTime object.

    I disagree - at the lowest level, Now.DateTime should be marked volatile, and there's nothing that allows the compiler to cache the static method invocation.

  • Walky_one (unregistered) in reply to kilroo
    kilroo:
    Walky_one:
    And as a little side effect you can even get nice stuff like 31 of february if you time it right.

    You're getting the month before the day.

    You're right. Just found that C# strictly defines the order in which the parameters are resolved (I originally thought it would be compiler magic...)

  • Walky_one (unregistered) in reply to anonymous
    anonymous:
    I feel like the compiler should be smart enough to know that a dozen different copies of Now.DateTime that aren't used more than once and have no explicit delay between their invocation should really all be the same DateTime object.

    So your in faver that the following code should "cache" the results of Now?

    Log("Starting at" + Now.ToString()); ExecuteSomeLengthyProcess(); Log("Finished at" + Now.ToString());

    This would then result in the following output "Starting at <some time="">&quot; <log entries="" of="" process=""> &quot;Finhshed at <same time="" as="" above="">&quot;<p> </same></log></some>

  • lorna (unregistered) in reply to DamienK

    Hashes should be xored, not added. Adding up evenly distributed values doesn't result in an even distribution.

  • Watson (cs)

    The first looks all too much like something I've seen in all too many PHP scripts.

    $year = date('y');
    $month = date('m');
    $day = date('d');
    $hour = date('h');
    $minute = date('i');
    $second = date('s');
    $time = mktime($hour, $minute, $day, $second, $month, $day, $year);
    

    With maybe a "$minute + 1" so that "$time" is one minute in the future - this being the point of the exercise. I'm willing to bet that "not exactly now" is less exactly now for PHP than for C#.

    Bonus points for those who set $minute to date('m').

  • EuroGuy (unregistered)

    My Java (?) is a bit rusty, but if I am not mistaken the == operator for StringString - and therefore also the equals method - will check that the key and values of two StringStrings are the exact same objects, rather than possibly different objects with identical values.

    Of course this may have been intentionded by the programmer, but it is counter-intuitive at the least for the equals method.

  • Dwedit (cs)

    For a reference type, the rule of GetHashCode is that is must never change, otherwise you can't put it in a dictionary/hashset as the key. But I guess it's okay for a value type.

  • Jeremy (unregistered)

    Surely there's no need to implement both == AND !=....right?

  • Remy Porter (cs)

    And the culprit of the string reverse comes clean. Pop over to Reddit and give him some karma to drown his sorrows.

  • Jay (unregistered)

    All this carping about the possibility of the date rolling over between calls to Now! This problem is easily fixed:

    public string SomeFunc() {
      DateTime NowTime = DateTime.Now;
      DateTime StartTime = new DateTime(NowTime.Year, NowTime.Month, NowTime.Day, 
        NowTime.Hour, NowTime.Minute, NowTime.Second, NowTime.Millisecond);
      //… do stuff
    }
    

    There!

  • Jay (unregistered) in reply to anonymous
    anonymous:
    I feel like the compiler should be smart enough to know that a dozen different copies of Now.DateTime that aren't used more than once and have no explicit delay between their invocation should really all be the same DateTime object.

    How would it know?

    If you write

    int hour=DateTime.Now.hour;
    int minute=DateTime.Now.minute;
    

    I'd guess you want the hour and minute for the same time. But

    DateTime startTime=DateTime.Now;
    doSomething();
    DateTime endTime=DateTime.now;
    

    You surely do NOT want the same time used in both cases.

    A human being looking at your code could probably make a good guess which you wanted, but how would the compiler know? The compiler isn't supposed to figure out the intent of your code, it's just supposed to do what you wrote.

    Didn't we just have a story on here about the computer being required to read the user's mind?

  • abarker (cs)

    Okay, the DateTime one is a WTF, but whoever submitted the "LINQ" one doesn't know their .NET.

    The Long Way:
    Now, though, we have a string that’s guaranteed to exist and be at least 6 characters long. We need to get the last six characters of that string. We could use a substring function, but that wouldn’t give us an opportunity to use our knowledge of LINQ functions. Kelly found this superior solution:

    public string LastSixDigits { get { if (string.IsNullOrWhiteSpace(this.Number) || this.Number.Length < 6) return string.Empty; return this.Number.Reverse().Take(6).Reverse().Aggregate(string.Empty, (s, c) => s += c); } }

    That isn't a LINQ function. It's a lambda function, as clearly indicated by the '=>' operator.

    Also, Remy should be ashamed (nothing new there). I took a look the source of the page, and he flagged this code as objective-C. This is clearly a .NET code block, whether it is a LINQ or lambda sample. Either way, an objective-C flag should never have come close to this code.

    Addendum (2014-05-01 10:38): Some references:

    LINQ Lambda Expressions

    Addendum (2014-05-01 12:13): CORRECTION: I forgot that LINQ can be used as standard function calls as shown in the code snippet. I haven't used LINQ in a while due to the standards where I work, but I get plenty of chance to use lambda expressions for cross threading purposes. Just goes to show we can all have stupid moments.

  • Jay (unregistered) in reply to Dwedit
    Dwedit:
    For a reference type, the rule of GetHashCode is that is must never change, otherwise you can't put it in a dictionary/hashset as the key. But I guess it's okay for a value type.

    Umm ... no. If the state of the object changes, I'd expect the hash code to change, or at least to possibly change.

    In this example, if the value of "key" is changed, I wouldn't want or expect the hash code to remain the same.

    If you're building a dictionary of these objects that is keyed by hash code, than it probably makes no sense for the has code NOR the key to change. It might or might not make sense for the value to change, depending on what you're doing. So you might say that once the object is created the key can never change, and that the hash code is derived only from the key. Or you might say neither key nor value can change. But I doubt I would allow the key to change but keep the hash code constant. That would not seem to make sense.

    If you're not building a dictionary and you can freely change the key and/or value of the object, then it would almost certainly not make sense for the hash code to be constant regardless of changes to the key and value.

    Maybe you could spin scenarios, depending on just what you're up to.

  • Valued Service (unregistered) in reply to Jeremy
    Jeremy:
    Surely there's no need to implement both == AND !=....right?

    It gives you a way to implement four way value for equality.

    a==b, a!=b T, T T, F F, T F, F

    So now you have to check both.

  • Jay (unregistered)

    All you people talking about just using substring instead of a complex LINQ function, or just saying time1=DateTime.now instead of writing a complex and involved function ... Oh, so you just want everything to be simply and easy! Wow, lazy people. If you don't do everything the hard way, how will you build character?

  • Valued Service (unregistered) in reply to Jay
    Jay:
    Dwedit:
    For a reference type, the rule of GetHashCode is that is must never change, otherwise you can't put it in a dictionary/hashset as the key. But I guess it's okay for a value type.

    Umm ... no. If the state of the object changes, I'd expect the hash code to change, or at least to possibly change.

    In this example, if the value of "key" is changed, I wouldn't want or expect the hash code to remain the same.

    If you're building a dictionary of these objects that is keyed by hash code, than it probably makes no sense for the has code NOR the key to change. It might or might not make sense for the value to change, depending on what you're doing. So you might say that once the object is created the key can never change, and that the hash code is derived only from the key. Or you might say neither key nor value can change. But I doubt I would allow the key to change but keep the hash code constant. That would not seem to make sense.

    If you're not building a dictionary and you can freely change the key and/or value of the object, then it would almost certainly not make sense for the hash code to be constant regardless of changes to the key and value.

    Maybe you could spin scenarios, depending on just what you're up to.

    You just walked in circles.

    If you imply a value is a key in code, and that it is used for the hash code, you shouldn't allow it or the hash code to change.

    That's just being a polite coder.

    The programmer should have just returned key in the hash.

    If they wanted to have both values in the hash, and intend the whole object to be a key, they should have just used the default object.GetHashCode();

    Either way, they've circumvented all the default logic that provably solves their problem.

  • tater (unregistered) in reply to Jay
    Jay:
    If you don't do everything the hard way, how will you build character?
    Well, that second function is certainly "building character"... one at a time.

    (ducks and runs) :-D

  • slicer (unregistered) in reply to abarker

    Interesting that Reverse(), Take() and Aggregate() all appear in the System.Linq namespace, if it isn't using LINQ functions. Not buying your logic on that.

    Captcha: usitas, as in "usitas la fuerza, Lucas!"

  • BA (unregistered) in reply to abarker

    "That isn't a LINQ function. It's a lambda function"

    What on earth does that mean? There's more than one call in that code snippet. Several of them are LINQ functions, one of which takes a lambda function as a parameter. Whatever made you think that you can't have LINQ and lambdas in the same code?

  • anonymous (unregistered) in reply to Walky_one
    Walky_one:
    anonymous:
    I feel like the compiler should be smart enough to know that a dozen different copies of Now.DateTime that aren't used more than once and have no explicit delay between their invocation should really all be the same DateTime object.

    So your in faver that the following code should "cache" the results of Now?

    Log("Starting at" + Now.ToString()); ExecuteSomeLengthyProcess(); Log("Finished at" + Now.ToString());

    This would then result in the following output "Starting at <some time="">&quot; <log entries="" of="" process=""> &quot;Finhshed at <same time="" as="" above="">&quot;</same></log></some>

    No, because there's code in-between the calls to get the system date & time. Even if you wrote this, it should use two different instances of Now, because the Log function has to execute in-between the two calls to get Now:

    Log("Starting at" + Now.ToString());
    Log("Finished at" + Now.ToString());

    But this should use only two instances of Now, not six:

    Log("Starting at " + Now.getHours() + ":" + Now.getMinutes() + ":" + Now.getSeconds);
    ExecuteSomeLengthyProcess();
    Log("Finished at " + Now.getHours() + ":" + Now.getMinutes() + ":" + Now.getSeconds);
  • abarker (cs) in reply to BA
    ba:
    abarker:
    That isn't a LINQ function. It's a lambda function

    What on earth does that mean? There's more than one call in that code snippet. Several of them are LINQ functions, one of which takes a lambda function as a parameter. Whatever made you think that you can't have LINQ and lambdas in the same code?

    Whoops, missed those. I haven't had a chance to use LINQ in a while due to the standards where I work, but I use plenty of Lambda expressions for cross-threading. Guess my rustiness in that area is showing this morning.

    My complaints about Remy tagging that code snippet as objective-C still stand though.

  • Nagesh (cs) in reply to abarker
    abarker:
    ba:
    abarker:
    That isn't a LINQ function. It's a lambda function

    What on earth does that mean? There's more than one call in that code snippet. Several of them are LINQ functions, one of which takes a lambda function as a parameter. Whatever made you think that you can't have LINQ and lambdas in the same code?

    Whoops, missed those. I haven't had a chance to use LINQ in a while due to the standards where I work, but I use plenty of Lambda expressions for cross-threading. Guess my rustiness in that area is showing this morning.

    My complaints about Remy tagging that code snippet as objective-C still stand though.

    Where did you see that tag?

  • Evan (unregistered) in reply to Jay
    Jay:
    anonymous:
    I feel like the compiler should be smart enough to know that a dozen different copies of Now.DateTime that aren't used more than once and have no explicit delay between their invocation should really all be the same DateTime object.

    How would it know?

    If you write

    int hour=DateTime.Now.hour;
    int minute=DateTime.Now.minute;
    

    I'd guess you want the hour and minute for the same time.

    To play devil's advocate for a second you could at least argue that the compiler should merge DateTime.Now objects iff there is no intervening sequence point. (I don't know if C# has the notion of sequence points, but let's roll with this for a sec.) So foo(DateTime.Now.Hours, DateTime.Now.Minutes,...) has no sequence point between DateTime.Now invocations so they would share an object, but yours does have a sequence point between them so they would be different objects.

    I think there are a number of reasons this is a kind of dumb suggestions, but the above would at least be workable...

  • Evan (unregistered)

    I forgot to say: for my suggestion to work, you'd perhaps have to define DateTime.Now.xxxx properties so that they didn't inject sequence points for purposes of that behavior.

  • Test (unregistered)

    What does compiler do with:

    log( "started " + now.hour + get_delimiter() + now.minute )

    or

    log( "started " + format( now.hour ) + ":" + format( now.minute ) )

  • TGV (cs) in reply to Tom
    Tom:
    public mutable fields are very bad; public mutable fields in a struct should be a firing offense.
    Are you one of those people that make every member private and then add public getters and setters that do nothing but { return member; } and { member = value; }?
  • Evan (unregistered) in reply to TGV
    TGV:
    Tom:
    public mutable fields are very bad; public mutable fields in a struct should be a firing offense.
    Are you one of those people that make every member private and then add public getters and setters that do nothing but { return member; } and { member = value; }?
    How are you supposed to run an enterprise if you willy-nilly make everything public?
  • David Mårtensson (unregistered) in reply to Evan
    Evan:
    To play devil's advocate for a second you could at least argue that the compiler should merge DateTime.Now objects iff there is no intervening sequence point. (I don't know if C# has the notion of sequence points, but let's roll with this for a sec.) So foo(DateTime.Now.Hours, DateTime.Now.Minutes,...) has no sequence point between DateTime.Now invocations so they would share an object, but yours does have a sequence point between them so they would be different objects.

    I think there are a number of reasons this is a kind of dumb suggestions, but the above would at least be workable...

    Well you could probably do that.

    But on the other hand, what if the code is explicitly written to identify IF the minute changed between the calls ;)

    I know, its extremely far fetched, but on the other hand, the compiler should not make guesses that actually change the behavior just in case.

    Imagine the horror of trying to debug it.

    That said, the editor could, like the resharper plugin for visual studio, high light the multiple calls and suggest that you merge them, but the decision must stay with the developer.

  • Remy Porter (cs) in reply to abarker
    abarker:
    Also, Remy should be ashamed (nothing new there). I took a look the source of the page, and he flagged this code as objective-C. This is clearly a .NET code block, whether it is a LINQ or lambda sample. Either way, an objective-C flag should never have come close to this code.

    Well, I didn't flag the code as Obj-C. The syntax highlighter we use flagged it that way. I should probably upgrade that- newer versions are supposed to have better detection.

  • Dan (unregistered) in reply to anonymous
    anonymous:
    I feel like the compiler should be smart enough to know that a dozen different copies of Now.DateTime that aren't used more than once and have no explicit delay between their invocation should really all be the same DateTime object.

    Sure. Computers are so accurate at correcting our text messages, so why not let them guess at what we really meant to code?

  • dkf (cs) in reply to EuroGuy
    EuroGuy:
    My Java (?) is a bit rusty
    Not Java. Java completely prohibits user-defined operator overriding. (The language designers reserved the <span style="color:black;font-family:monospace;">operator</span> keyword and refuse to give it a place in either the syntax or the semantics. That way lies madness; that way lies C++…)
  • Anonymous Will (unregistered) in reply to lorna
    lorna:
    Hashes should be xored, not added. Adding up evenly distributed values doesn't result in an even distribution.

    Yes, it does, because int addition is modulo 2^32.

  • chubertdev (cs) in reply to Anonymous
    Anonymous:
    If you're interested, here's the IL code generated with LINQPad 4, with optimization on:
    IL_0000:  ldloca.s    00 // StartTime
    IL_0002:  call        System.DateTime.get_Now
    IL_0007:  stloc.1     // CS$0$0000
    IL_0008:  ldloca.s    01 // CS$0$0000
    IL_000A:  call        System.DateTime.get_Year
    IL_000F:  call        System.DateTime.get_Now
    IL_0014:  stloc.2     // CS$0$0001
    IL_0015:  ldloca.s    02 // CS$0$0001
    IL_0017:  call        System.DateTime.get_Month
    IL_001C:  call        System.DateTime.get_Now
    IL_0021:  stloc.3     // CS$0$0002
    IL_0022:  ldloca.s    03 // CS$0$0002
    IL_0024:  call        System.DateTime.get_Day
    IL_0029:  call        System.DateTime.get_Now
    IL_002E:  stloc.s     04 // CS$0$0003
    IL_0030:  ldloca.s    04 // CS$0$0003
    IL_0032:  call        System.DateTime.get_Hour
    IL_0037:  call        System.DateTime.get_Now
    IL_003C:  stloc.s     05 // CS$0$0004
    IL_003E:  ldloca.s    05 // CS$0$0004
    IL_0040:  call        System.DateTime.get_Minute
    IL_0045:  call        System.DateTime.get_Now
    IL_004A:  stloc.s     06 // CS$0$0005
    IL_004C:  ldloca.s    06 // CS$0$0005
    IL_004E:  call        System.DateTime.get_Second
    IL_0053:  call        System.DateTime.get_Now
    IL_0058:  stloc.s     07 // CS$0$0006
    IL_005A:  ldloca.s    07 // CS$0$0006
    IL_005C:  call        System.DateTime.get_Millisecond
    IL_0061:  call        System.DateTime..ctor
    

    See, the compiler doesn't optimize the code. Not sure if the JIT does that, but probably not since DateTime.get_Now is not a pure function

    This is the type of comment that I was hoping for when I submitted the snippet. Thank you!

Leave a comment on “The Long Way”

Log In or post as a guest

Replying to comment #:

« Return to Article