Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I have a survey that is 40 questions in length. All of them are arrays and look like q1 q2 q3 ... q10 q11 q12... upto q40.

So the variable I want to create will look like my $q1, my $q2 and so on and so on. And the params are identical, they are also param("q1"), param("q2), etc. I don't want to hard code every bloody variable in there and was wondering if this could be done by a loop to create and assign all of these variables?

I was thinking something like

my $cnt = 0; for ( 1 .. 40) { $cnt++; my $q$cnt = param("q$cnt"); }
But under strict, the variables would only be accessibly until the loop is over. Can anyone come up with a way to do this?

Replies are listed 'Best First'.
Re: creating variables in a loop
by merlyn (Sage) on May 18, 2005 at 22:30 UTC
    No, you really don't want to do that. You only think you want to do that. Instead, you want a hash, with keys of "q1" through "q40". Or even an array where elements indexed 1 to 40 are your values. That'd be something like this:
    my @q; for (1..40) { $q[$_] = param("q$_"); }

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

Re: creating variables in a loop
by davido (Cardinal) on May 19, 2005 at 00:21 UTC

    Decades of advances in the science of computer programming have brought us to a point in language development where variable variable names have become both shunned, and in most languages, not even possible. This has come to be the case for very good reasons, thought up by some smart people, and punctuated by the collective experience of many many more average people as well as a few dummies along the way who got lucky.

    Perl is one of those languages that has benefitted from the collective experience of the decades, along with the specific knowlege of a few really smart people. And that is how Perl came to have a pragma known as 'strict'. Strictures are Perl's way of keeping you from falling into the pit of despair that can come from venturing down the road of symbolic references without the realization that there is almost always a better approach. Now this isn't to say that some really really smart people (and a few average lucky ones) haven't come up with some darn good uses of symbolic references in Perl. And in fact Perl's designer(s) have left us with the capability to use them, unlike many other languages. But the odds are very strong that this isn't one of those times where it could be considered a good idea to use them.

    Use an array of fourty members, or use a hash. You know, Perl's global variables themselves belong to a global symbol table hash. If it's good enough for Perl, it's good enough for you too... but don't muck with Perl's hash, get your own. :) Just because the neighborhood has its own gate doesn't mean that you shouldn't have a lock on your front door too...


    Dave

Re: creating variables in a loop
by mrborisguy (Hermit) on May 18, 2005 at 22:29 UTC

    First, I must suggest using an array. That would be the most simple. Then all you would need would be:

    my $cnt = 0; my @q; for ( 1 .. 40 ) { $cnt++; $q[ $cnt ] = param( "q$cnt" ); }

    If you are DYING to use variables named $q11, etc., it is possible. However, I recently maintained a webpage that went with this method, and I was pretty close to strangling the original writing and yelling at him to learn how to use arrays (but I refrained). Anyway, enough with my story, to do that, you would need to do something like this (I think, this is untested, and I don't know what the scope will be).

    my $cnt = 0; for ( 1 .. 40 ) { $cnt++; eval( "my \$q$cnt = param( \"q\$cnt\" );" ); }

    I do think you would be better off with an array in the end. I can not think of any good reason that you would necessarily need to have 40 seperately named variables instead of one array.

    -Bryan

    Update:
    Removed 'my' from first example, thanks to merlyn pointing out my error.

      merlyn's points aside, it's still broken because you still have a my inside your eval'd string and the lexical will disappear with the BLOCK of the enclosing for.

      $ perl -le 'use strict; for( 1..2 ) { eval qq{my \$q$_ = $_}; }; print + $q1' Global symbol "$q1" requires explicit package name at -e line 1.

        Yes, of course I remember what you said. In this case, in my example, it's not a security flaw. I can tell you exactly what $cnt is going to be every time, and everything else is escaped.

        I presented it as an answer to his question. I thought your bias on eval was because of security, not absolutely against any use of eval, but maybe I was mistaken?

        -Bryan