http://qs1969.pair.com?node_id=425481

j.goor has asked for the wisdom of the Perl Monks concerning the following question:

Fellow Monks,
Consider my next question a very basic question, purely for my own fun:
What is better or more preferred in the next example (and why?):
A)
my $T; if ($hour > 12) { $hour -= 12; $T = 'PM'; } else { $T = 'AM'; }
Or:
B)
my $T = 'AM'; if ($hour > 12) { $hour -= 12; $T = 'PM'; }
See the detail?
I was wandering what 'solution' would be better, since I run into these kind of thing regularly and it made me curious if there would be a 'common' way to handle this.
Rgds,
John

Replies are listed 'Best First'.
Re: Basic programming question
by samizdat (Vicar) on Jan 27, 2005 at 13:08 UTC
    You're asking whether an assignment then a possible re-assignment is 'better' than an if-then-else with a single assignment. Yes?

    My question to you (building on another AM's) is what your criteria is? Is it readability and maintainability? Or, is it speed? In this trivial case, speed is pretty much a wash. Were you to be doing multiple assignments, however, it might be better to use A than B. In either case, the difference in CPU time per branch is minimal and not a factor.

    As a coder who more often than not gets down to assembly, I'm used to B, and I think most coders are. As long as you don't need to make a flowchart for Management, B is every bit as usable as A from the maintainability standpoint.
Re: Basic programming question
by Hena (Friar) on Jan 27, 2005 at 07:01 UTC
    Since 24 hour clock is better than 12, i would ignore AM and PM thingies :). But in general (eg program structure in any similar situation), I would go with B is possible. It's more readable in my opinion.
Re: Basic programming question
by ysth (Canon) on Jan 27, 2005 at 07:09 UTC
    Assuming $hour is 0..23 initially,
    my $T; for my $hour (0..23) { print "in: $hour "; if ($hour > 11) { $T = 'PM'; } else { $T = 'AM'; } ($hour %= 12) ||= 12; print "out: $hour $T\n"; } __END__ in: 0 out: 12 AM in: 1 out: 1 AM in: 2 out: 2 AM in: 3 out: 3 AM in: 4 out: 4 AM in: 5 out: 5 AM in: 6 out: 6 AM in: 7 out: 7 AM in: 8 out: 8 AM in: 9 out: 9 AM in: 10 out: 10 AM in: 11 out: 11 AM in: 12 out: 12 PM in: 13 out: 1 PM in: 14 out: 2 PM in: 15 out: 3 PM in: 16 out: 4 PM in: 17 out: 5 PM in: 18 out: 6 PM in: 19 out: 7 PM in: 20 out: 8 PM in: 21 out: 9 PM in: 22 out: 10 PM in: 23 out: 11 PM
Re: Basic programming question
by dragonchild (Archbishop) on Jan 27, 2005 at 16:37 UTC
    I'd look for someone who's solved the problem before and use their solution. In this case, DateTime, Date::Calc, and/or Date::Manip are all excellent solutions to this problem (and the general problem of dates and times).

    In most other situations, you will realize you're solving a problem others have already solved. In the other cases, use a dispatch table or a trinary.

    Being right, does not endow the right to be rude; politeness costs nothing.
    Being unknowing, is not the same as being stupid.
    Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
    Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

Re: Basic programming question
by davido (Cardinal) on Jan 27, 2005 at 06:45 UTC

    Both are in error, since PM starts at 12:00, mid-day.

    Without additional context it's difficult to cast judgement on which approach is the lesser of two evils.


    Dave

      That's debatable ;) I've seen arguments each way. Here's one from greenwichmeantime.com:

      AM and PM start immediately after Midnight and Noon (Midday) respectively.

      This means that 00:00 AM or 00:00 PM (or 12:00 AM and 12:00 PM) have no meaning.

      Every day starts precisely at midnight and AM starts immediately after that point in time e.g. 00:00:01 AM (see also leap seconds)

      To avoid confusion timetables, when scheduling around midnight, prefer to use either 23:59 or 00:01 to avoid confusion as to which day is being referred to.

      It is after Noon that PM starts e.g. 00:00:01 PM (12:00:01)

        That may be, but j.goor is testing to see if the hour is greater than 12. If the hour is greater than 12, it's either 1:00pm or 1300, which is just about a full hour past the AM/PM meridian.

        If the script is using $hour to mean hours and decimal hours, that sort of thing is not obvious in the snippet provided. What it says is that it is looking at hours.


        Dave

Re: Basic programming question
by tall_man (Parson) on Jan 27, 2005 at 16:31 UTC
    There are several reasons to prefer B to A, IMHOP.

    1) It is good practice to apply the principle of initializing variables to valid values as soon as they are declared.

    2) The second way is more efficient. You avoid generating the code for entering an extra scope level (the else).

    3) You may think the first way is avoiding an assignment to $T but that is not the case. Code is generated to assign an undef to it. (Update: I think I was mistaken about this one.. But the extra assignment cost is neglibible.)

    4) It is just as readable, if not more so. You can view "AM" and an unmodified hour as the default, and "PM" with a subtracted hour as the exception.

    Try running both these codes with "perl -MO=Terse" and you will see the differences.

Re: Basic programming question
by kiat (Vicar) on Jan 27, 2005 at 12:03 UTC
    I would go with (B), since the else bit is merely assigning AM to $T.

    I don't know whether it's programmtically better. I've code like that too and I use style (B).

Re: Basic programming question
by sleepingsquirrel (Chaplain) on Jan 27, 2005 at 16:32 UTC
    Perl has a special conditional operator (the ternary ?:) which is custom made for just this type of thing.
    my $T = ($hour > 12) ? "PM" : "AM";
    update: Whoops, just noticed that the OP is also decreasing $hour for the "PM" case. In that case, the ternary operator becomes a little more ugly.
    my $T = ($hour > 12) ? do {$hour-=12; "PM"} : "AM";
    Your best bet is probably one of the CPAN modules like dragonchild recommends.


    -- All code is 100% tested and functional unless otherwise noted.
      You missed subracting from the hour with this substitution. Update: The update fixes the problem, but I still prefer the simpler options like B for readability.
Re: Basic programming question
by Anonymous Monk on Jan 27, 2005 at 10:52 UTC
    I was wandering what 'solution' would be better, since I run into these kind of thing regularly and it made me curious if there would be a 'common' way to handle this.
    That's not an interesting question, and until this far, none of the answers given are very helpful in answering the question.

    It's also a very, very open question. You're very specific about the (hardly relevant) details -- the code --, but expect the six letters to name it, "better", you don't discuss the main thing at all.

    How do you expect this forum to answer your question, if you don't describe at all what you mean by "better"? Better in which way? Faster? Less memory? Less code? Or do you measure in more subjective ways, like easier to understand (which is of course a hopeless question to ask).

    If you want to advance yourself in programming, don't come up with two pieces of code, and ask others what the better code is. You'll get little out of it. Instead, analyse the pieces of code yourself, and come up with reasons why you want to one piece and why you want to use the other piece of code.