To constant or not to constant, that is the question



  •  So I was browsing SO and stumbled on this question http://stackoverflow.com/questions/11/how-do-i-calculate-relative-time. The accepted answer defines things like seconds, minutes, etc like so:

     "Jeff, your code is nice but could be clearer with constants (as suggested in Code Complete).

    const int SECOND = 1;
    const int MINUTE = 60 * SECOND;
    const int HOUR = 60 * MINUTE;
    const int DAY = 24 * HOUR;
    const int MONTH = 30 * DAY;
    "

    This gave me deja vu. This is the kind of thing people usually laugh at in here. The usual sarcastic comment is "good thing he declared that constant cause you never know when the number of seconds in a minute might change", etc. And yet the answer to the SO question makes sense to me.

     

    What do you guys think?

     


  • Discourse touched me in a no-no place

    @DOA said:

    const int DAY = 24 HOUR;
    What about leap seconds? (though strictly speaking, that would probably apply better to YEAR, which is missing from the example.)

    @DOA said:
    const int MONTH = 30 DAY;
    February?

    @DOA said:
    This is the kind of thing people usually laugh at in here. The usual sarcastic comment is "good thing he declared that constant cause you never know when the number of seconds in a minute might change", etc.
    Well, yes, we laugh, but not for the reason you suggest for this one.



  • @DOA said:

    What do you guys think?

    The alternatives are to write out the familiar numbers  (60 * 60 * 24)  every time in calculations, or the unfamiliar product 86400.

    The first is cumbersome, the second amounts to a magic number.

    I'd go for a named variable.



  • @dhromed said:

    @DOA said:

    What do you guys think?

    The alternatives are to write out the familiar numbers  (60 * 60 * 24)  every time in calculations, or the unfamiliar product 86400.

    The first is cumbersome, the second amounts to a magic number.

    I'd go for a named variable.

    I agree with dhromed, which means he must have an intelligence score of at least 8.  Since he usually demonstrates an intelligence of 3 or 4, he's probably been posting while hopped up on Mentats again.


  • @bstorer said:

    Since he usually demonstrates an intelligence of 3 or 4, he's probably been posting while hopped up on Mentats again.
     

    It's the other way around, and it's 10% ABV beers.


  • ♿ (Parody)

    There's a fine line that depends on specificity and language.

    Clearly, it's a best practice that domain-specific constants should made into variables in well-typed languages; it's not that they'll ever change, but this way you can ensure that constants are not miskeyed ("cancelled" vs "canceled"). Plus, there's the benefit of IntelliSense-like stuff.

    For example (from a recent project)...

            /// <summary>
            /// List of commands
            /// </summary>
            protected static class HgCommands
            {
                /// <summary>
                /// add the specified files on the next commit
                /// </summary>
                public const string add = "add";

                /// <summary>
                /// add all new files, delete all missing files
                /// </summary>
                public const string addremove = "addremove";

                /// <summary>
                /// show changeset information by line for each file
                /// </summary>
                public const string annotate = "annotate";

                /// <summary>
                /// create an unversioned archive of a repository revision
                /// </summary>
                public const string archive = "archive";

                ...
            }

    Doing this in dynamic language, however, wouldn't offer much benefit and would likely lead to more errors. It's just as easy to inconsistantly spell canceled in a constant as it is a string.

    But given this specific example of a single function to calculate time (i.e. .NET and non-domain specific), there's no benefit of abstracting out of the method scope (i.e. making a static class TimeConstants), since this is probably the only place it will be used. That said, it comes down to readability.

    I would argume that "DAY" is not a very good name; it should be SecondsPerDay. So, given that, what's more readable?

        if (value < SecondsPerDay)

    ...or...

        if (value < 60 * 60 * 24) //Seconds per day

    Since they're equally readable/maintainable, and the former creates more LOC, I'd go with the latter. Less code = better.



  • @Alex Papadimoulis said:

    I would argume that "DAY" is not a very good name; it should be SecondsPerDay. So, given that, what's more readable?
     

    I agree in principle, and I would do it if I worked on something with you, but I don't feel it strongly enough to change existing code if I stumbled upon it.



  • So, the variables of interest hold time (or duration). In seconds. But why must the unit be seconds? What happens if you later realise your program need milisecond precision, so the variables ought to hold time in miliseconds.Much of the work can be done by simply changing to this:

    const int SECOND = 1000;

     



  • @Raedwald said:

    So, the variables of interest hold time (or duration). In seconds. But why must the unit be seconds? What happens if you later realise your program need milisecond precision, so the variables ought to hold time in miliseconds.Much of the work can be done by simply changing to this:

    const int SECOND = 1000;

     

     

    Statistically speaking, what happens is that after a few hours you'll realise you just broke everything. What once was stored as 1 * MINUTE = 60, is now read back as 60 = 0.06 * SECOND. That's why you should use a reliable library with constant time units, not something you wrote in 10 minutes with "constant but can change in future" time units

Log in to reply