Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number

Using aliases in for loops or not?

by jkva (Chaplain)
on Feb 17, 2005 at 08:57 UTC ( #431859=perlquestion: print w/replies, xml ) Need Help??
jkva has asked for the wisdom of the Perl Monks concerning the following question:

UPDATE : Got the description of the variable wrong.
Monks of the perl code,

this humble novice once more would request you to look up from your tomes and spare this unworthy son a few moments of your valuable time.

For some time now, I find myself among your midst. When I first came in here, I donned my robe with pride and shared much interesting times in this monastery, which has become my home away from home, and I have gained much knowledge.

Though still, from time to time, I notice small errors in my code. They are not fatal, wise ones, yet they are inefficient use of code which could be great, if only for knowledge I yet not posess.

Earlier today, I discovered such an error. It was as such:($data is a reference to an array of references to arrays)

foreach my $record(@$data) {print @$record[0];}
This is how my code used to be. Today, to see if it could be done, I wrote this:

foreach(@$data) {print @$_[0];}
Which, to my surprise, worked!. This proves all my previous code could contain these horrid unefficiencies.
I have been taught the holy verse of TMTOWTDI, but still, this I must ask, where lie the boundaries of efficient and inefficient code? Was this bad code? What should be paid attention to when writing code?

I realize that this question addresses a very broad spectrum, which I ask your forgiveness for. Still, I felt I had to ask it. I must learn in order to know.

Your fellow scribe,

-- Detonite

Replies are listed 'Best First'.
Re: A question for the enlightened.
by saintmike (Vicar) on Feb 17, 2005 at 09:16 UTC
    First off, let's get one thing out of the way: @$record[0] is just horrible. Never use an array slice if you want an array element, that's just plain wrong. $$record[0] is probably what you want. But doesn't $record->[0] look much better?

    As for using variables to iterate over an array or using the implicit $_, that's actually debateable. If you're using $_ downstream via regex matching (conveniently done as /.../ as opposed to $record =~ /.../), using the implicit iterator saves some keystrokes. But for all other purposes, I find named iterator variables easier to read. YMMV, of course.

      Thanks for the reply.
      Uh, "YMMV"? ;)

      I was under the impression that I now used a variable ($record) while it was not needed. Which is memory allocation while not needed, which is inefficient. Or am I wrong on this point? I *do* agree that it is more readable though.


      -- Detonite

        Before saying "it's inefficient", did you benchmark it?
Re: Using aliases in for loops or not?
by theorbtwo (Prior) on Feb 17, 2005 at 11:22 UTC

    There's an old adage -- a good programmer can write FORTRAN in any language. You are programming assembley in perl, which is just silly. One of the basic bits of the Perl attitude is that you shouldn't worry about the little things, and that programmer time is a lot more valueable then CPU time, bytes in RAM, or bytes on disk. Using the implicit $_ is often trading a very little bit of CPU time for a lot of programmer time, spent looking on in confusion at code that makes little sense.

    The other problem is that you are witing a slice that will always get only a single element. That's a big innefficency, and one perl would warn you about had you begun your script with use warnings;. There is a temptation to leave this out that I suspect you will feel -- the temptation to say "but I'm writing what I meant! It's valid code! Perl doesn't know better then me!". While it is true for some people that perl does not know better then you, in many cases, it really does, especially when one is starting out.

    The best way to write a piece of code is generally the way that fits the way you think about it. If you think "print the first element of each array referenced from @$data", print $_->[0] foreach @$data;. If you think "loop over @$data, and print out the first element of each array it references",

    foreach ($@data) { print $_->[0]; }
    . On the third hand, if there was more stuff in there, then you have little choice but to use the second form, and if there's more then a couple lines, use an explicit loop variable. It /may/ be /slighty/ less efficent, but it's much easier to read.

    Warning: Unless otherwise stated, code is untested. Do not use without understanding. Code is posted in the hopes it is useful, but without warranty. All copyrights are relinquished into the public domain unless otherwise stated. I am not an angel. I am capable of error, and err on a fairly regular basis. If I made a mistake, please let me know (such as by replying to this node).

      I wonder if it really is an array slice...

      printing @x[0] will create a warning because an array slice is used. @$x[0] will not...

      On the other hand, @$x[0, 1] will return two elements what suggest that it is indeed an array slice...

Re: A question for the enlightened.
by monkey_boy (Priest) on Feb 17, 2005 at 10:20 UTC
    who cares about efficiency on this scale!, readabiltiy must be more important than shaving off a few micro-seconds (if that),
    also what do you do with nested for loops? your soon going to get confused if you dont alias $_.

    Im so sick of my Signature...
      Assembler programmers would spin in their graves generating electricity if they read this. Like I said in my previous post, it's the mindset that's important. Yes, they might me micro-secs, but micro-secs nonethless.

      I do not see where I am using a nested for loop though. It's just a foreach.

      -- Detonite

        Assembler programmers wouldn't program in Perl.

        The mindset is indeed important. And it's very important to program in a language that fits ones mindset. If your mindset is that microseconds are important, Perl is the wrong language for you.

        As for the actual differences:

        #!/usr/bin/perl use strict; use warnings; use Benchmark 'cmpthese'; our @array = (1 .. 1000); foreach my $x (1 .. 10) { cmpthese -1, { alias => 'my $c = 0; foreach (@array) {$c += $_}', variable => 'my $d = 0; foreach my $var (@array) {$d += $var}' +, }; } __END__ Rate alias variable alias 3139/s -- -3% variable 3230/s 3% -- Rate alias variable alias 3139/s -- -2% variable 3199/s 2% -- Rate alias variable alias 3139/s -- -0% variable 3140/s 0% -- Rate alias variable alias 3140/s -- -0% variable 3143/s 0% -- Rate alias variable alias 3110/s -- -5% variable 3262/s 5% -- Rate alias variable alias 3083/s -- -5% variable 3229/s 5% -- Rate alias variable alias 3131/s -- -3% variable 3229/s 3% -- Rate alias variable alias 3083/s -- -5% variable 3229/s 5% -- Rate variable alias variable 2821/s -- -10% alias 3140/s 11% -- Rate alias variable alias 3140/s -- -2% variable 3200/s 2% --
        You'd need to do some very careful analysis before deciding which of the two will save you some micro-seconds. Your analysis isn't based on anything. Just because something isn't in the code doesn't mean it isn't done.
        Your not, but given that foreach is just an alias to for, what do you do with nested foreach loops!

        Im so sick of my Signature...
Re: Using aliases in for loops or not?
by Animator (Hermit) on Feb 17, 2005 at 10:56 UTC

    Writing it like this (using array slice instead of scalar) (deefering an array-reference just to get one element) is bad.

    Why? Simple, it looks too complex.

    The bottomline is that you should use $array_reference->[index] instead of @array_reference[$index]. If you want more information about references then you shold read: `perldoc perlreftut` and/or `perldoc perlref` and/or `perldoc perldsc`.(updated)

    Here is a possible mis-interpretation of the code.

    One can think that the array-reference stored in $record[0] is being de-referenced and that that array is printed.

    Ofcourse this is impossible, since $record belongs to the foreach loop, so must be a scalar, and therefor $record[0] can never refer to the first element in this 'array', but someone that does not has that much knowledge about Perl might see it that way... (if it would refer to it it has to be $record->[0])

    And if you do that, you might be confusing a (new) Perl-user, which is not a good thing...

    For the part of wasting memory, I do not think that foreach $record (@x) uses more memory then foreach (@x).

    Unfortunally I do not know what happends when this code is executed (that is, what happends internally). But one possibility would be that $record is replaced with the actual variable of @x... (since it is an alias, every modification of $record will modify the element in the array!). This could be implemented in Perl by using a C-pointer, which would mean you are only wasting a few bytes .

    Update: Some mis-interpreatations... (a post above confused me by talking about an array slice, which is not correct).

      Thanks Animator, this is very useful.
      I will get my @camelids books out and read up on it. It is kinda obvious I need to, since I don't get all of the points you're making ;)

      -- Detonite

Re: Using aliases in for loops or not?
by jkva (Chaplain) on Feb 17, 2005 at 11:32 UTC
    The replies I got have shown me that there is indeed a long way to go.
    I see several code examples that are way more efficient than code I have written so far. Well, this was the goal of my post, a discussion about efficiency, so I am quite satisfied.

    A thing that's in the back of my mind though is that if Perl isn't very bitpicky, it is probably not the language for me. I want to code as efficient as I can, otherwise, what's the use? It will be bad code since it could have been written better.
    I do like to write code in it tho, mainly because the ternary operator, unless and things like that.
    I will ponder on this.

    -- Detonite

      if Perl isn't very bitpicky, it is probably not the language for me. I want to code as efficient as I can, otherwise, what's the use? It will be bad code since it could have been written better.
      You have been deceived into thinking that there is one measure of goodness for code, and that is CPU-cycle efficiency. Do not be lured by that oversimplistic view. Micro-optimization is the seductive siren of the Dork Side.

      Evaluating the quality of code is something like a beauty contest. Putting everything on how fast it runs is like deciding the winner based on how fast she answers the interview question. There's a degree to which speed matters, but more important is whether the answer satisfactorily addresses the question. And what about the swimsuit competition? Does your code provide complete coverage with a minimum of excess? Or the eveningwear: is it so elegant and appealing that you'd want to show it off to your friends?

      And don't underestimate congeniality. Programs that don't get along with other programs are not winners.

      Caution: Contents may have been coded under pressure.

      Writing efficent code is important. But it's far more important to write code efficently. Which is a more important optimization problem:

      1. Write a program to do such-and-such. You have a month, after which we will time everybody's program, and the fastest program wins.
      2. Write a program to do such-and-such. The first person to finish a program that can do it wins.

      Perl isn't a good language for writing fast code in. It is a good language for writing code in fast. That isn't to say you ignore computer-time-efficency issues... but you worry about the ones that cause 10% slowdown, and not 0.001% slowdown. If you need more speed, then you start worrying about the readability-vs-execution-speed tradeoffs, or rewrite the bits that need more speed in C.

      Of course, nothing in this node is to be taken too literally. I'm exagerating for effect. But think long and hard about it.

        Perl isn't a good language for writing fast code in.

        If I agreed with this I'd be disappointed - the perl porters put a lot of effort into improving the speed of perl, and trying to avoid speed loss.

        It is true that perl wouldn't be a good choice for an interrupt handler (say), where you need to be able to impose very tight bounds on average and maximum latency.

        However I have written lots of code that needed to be fast simply because it was doing an awful lot of work - the sort of recursive calculations that require billions of iterations - and I've found perl fine for such work. And for those cases, shaving a few microseconds can make a noticeable difference.

        Similarly, when some code will create many millions of in-memory records, the few bytes-per-record saving that means you don't start swapping can also make a big difference.

        I think the assembler background does give a helpful tint to the mindset, in that you get into the habit of applying the various micro-optimisations automatically, and the benefits do mount up.

        The important thing though is to keep a balance, and not let the optimisations affect readability (hence maintainability) too much; and to remember that finding a slightly better algorithm will likely put all the micro-optimisations into the pale.


Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://431859]
Approved by K_M_McMahon
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others surveying the Monastery: (11)
As of 2018-06-21 10:32 GMT
Find Nodes?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?

    Results (118 votes). Check out past polls.