in reply to On Foreach Loops and Maintainability

I prefer the first. At a glance, I can see that it's every element of the sequence, and that they're extremely regular. When you list them all explictly, I have to stare at each one to see if it's one higher than the previous and doesn't have some typo.

"Capture regularities in code, irregularities in data", is the koan of the senior programmer. You've bucked that for a microoptimization.

But yes, I understand your maintenance concern. Suppose besides "arg1".."arg5" (which is another way you could have written that and didn't, which made me wonder), you eventually might have had "arg19" and "gee37". You could have written the original loop as:

for (map("arg$_", 1..5)) { .. }
And then the maintenance person can add:
for (map("arg$_", 1..5, 19), "gee37") { .. }
That'd probably be the most flexible, and the most clear.

-- Randal L. Schwartz, Perl hacker

Replies are listed 'Best First'.
Re: •Re: On Foreach Loops and Maintainability
by dws (Chancellor) on Oct 11, 2002 at 19:15 UTC
    You could have written the original loop as:
    for (map("arg$_", 1..5)) { .. }
    That was my first though, but on further reflection, it looks like configuration information (i.e., which form fields we're interested in) is getting mixed into the code. Is this a bad thing? Perhaps. If the fact that we're interested into "arg1" .. "arg5" (and might later be interested in "arg19" or "gee37") appears elsewhere in the code, then lifting that information out into a configuration section would make maintenance safer.   my @formArgs = map { "arg$_" } 1..5; and then, later in the code
    foreach ( @formArgs ) { .. }
Re^2: On Foreach Loops and Maintainability
by Aristotle (Chancellor) on Oct 11, 2002 at 17:53 UTC

    <aol>me too</aol>

    And to take this a bit further, if there's no else, I'd write this like so:

    for (map("arg$_", 1..5, 19), "gee37") { $object->method($_) or next; # ... }

    Fewer indentation levels are generally easier to read. Finding this at the bottom of a function always makes me scroll up and down a couple times:

    # ... } } } # play "guess the block this belongs to" here $_ .= "something"; } } }

    Makeshifts last the longest.

      Is there a reason that the idea merlyn mentioned (that I think is a excellent use of perl) was comprehensively glossed over?

      I'd also try and do away with the if block but I think cond or next; reads a little unintuatively and would probably use
      next unless cond;

      for ( 'arg1' .. 'arg5', "arg19", 'gee13' .. 'gee37' ) { next unless $object->method( $_ ); # do stuff }

      Cor! Like yer ring! ... HALO dammit! ... 'Ave it yer way! Hal-lo, Mister la-de-da. ... Like yer ring!
        It depends on what I want to emphasize: I use EXPR or next; when a failure at that point is the exception. Of course, looking back at the original poster's code, there's nothing that says it is - and if not, I agree, I'd use a next if. I do so 95% of the time anyway. The flexibility of Perl's syntax allows a natural way of conveying emphasis, and I try to make use of that when appropriate. "Self explanatory" is usually my top goal.

        Makeshifts last the longest.

Re: &bull;Re: On Foreach Loops and Maintainability
by jordanh (Chaplain) on Oct 12, 2002 at 13:44 UTC
      "Capture regularities in code, irregularities in data", is the koan of the senior programmer. You've bucked that for a microoptimization.

    To me, it seems that your approach is working against this maxim. You are embedding the irregularities in the code. Sure, they are data in the code, but you have to work out that fact because you build up a list of 1-5 and 19 and attach gee37 to the end of it.

    I think that this:

    @obj_args = qw/ arg1 arg2 arg3 arg4 arg5 arg19 gee37 /; for ( @obj_args ) { ... }

    Is clearer. In this example, you've clearly separated the irregularities into a data structure and used that to drive the code.

    This kind of separation has all kinds of maintenance advantages, not just clarity on first reading. Say the maintenance programmer is confronted with a case where the arguments arg3 and gee37 have strange behavior. It's easy to change the code for this and you're doing it in such a way as to make it very clear if someone else working with the maintenance programmer would immediately grasp the intent.

    I much prefer:

    # @objargs = qw/ arg1 arg2 arg3 arg4 arg5 gee37 /; # # test just arg3 and gee37 @objargs = qw/ arg3 gee37 /; for ( @objargs ) { ... }

    To this:

    #for (map("arg$_", 1..5, 19), "gee37") { # # test just arg3 and gee37 for ( qw/ arg3 gee37 / ) { ... }

    This shows how the irregularity of the data is more clearly separated from the code. When you use something like:

    (map("arg$_", 1..5, 19), "gee37")

    You are using code to represent the irregularity of the data.