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

Good day great monks,
I wonder whether it's possible to create a variable for
each member of an array. For example:
for (1..10){ $num$_=$_; }
Whay I wanted to achieve above is 10 variables $num1,$num2
and so on...
How it's possible, if at all?
Thanks a lot in advance!

The problem I'm trying to solve is this:
I'm creating Buttons on Tk widget.
$but1=$mw->Button(-text=>"something",-command=>\&something1)->pack;
So instead creating each button, I'm trying to create them from array.
I must to be able to destroy/recreate these buttons.
Any suggestions?
Is it possible to have 10 different variables:
$num1,$num2,$num3,$num4..$num10
from my first code example? Thanks

Replies are listed 'Best First'.
Re: Creating variables for each array member
by Corion (Patriarch) on Jul 25, 2006 at 06:43 UTC

    While this is possible, you don't want that. Read Why it's stupid to use a variable as as a variable name to get a discussion of the perils and the solutions.

    You should put your data into an array instead of collecting it into numbered variables.

    I'm quite confident that somebody will show you the way how to use strings as variable names, but you shouldn't use that but first think long and hard about the problem you're trying to solve, and the alternatives that Perl offers you, like hashes and arrays. If an array does not suit your needs, then a hash sure will:

    my %numbers = ( num1 => 1, num2 => 2, ... num10 => 10, ); # which can be constructed programmatically as: my %numbers = map { "num$_" => $_ } (1..10);
      That's a really interesting answer ! thanks !
      i've also asked myself a lot of time how i could do that, and never thought it could be so buggy. From your link, my answer to this :

      On the other hand, I could try to answer on a different level, present a better solution, and maybe slap a little education on `em. That's nice when it works, but if it doesn't it's really sad to see your hard work and good advice ignored.
      I really do prefer when people just tell me i'm on a wrong way, the time you think you lose in learning a new concept isn't losed most of the time.

      A huge thank to all people who take time for this !

      Marsel

Re: Creating variables for each array member
by Zaxo (Archbishop) on Jul 25, 2006 at 06:41 UTC

    It's possible, but you shouldn't. Use your digits as array indexes, instead.

    my @num; for (1..10) { $num[$_] = $_; }

    When you want lots and lots of automatically generated scalar variables, you nearly always really want a hash or an array, instead.

    After Compline,
    Zaxo

Re: Creating variables for each array member
by GrandFather (Saint) on Jul 25, 2006 at 10:04 UTC

    Use an array:

    use warnings; use strict; use Tk; my $main = MainWindow->new (-title => "ButtonDemo"); my @buttons; push @buttons, $main->Button (-text => "Button $_") for 1..10; $_->pack () for @buttons; MainLoop ();

    DWIM is Perl's answer to Gödel
Re: Creating variables for each array member
by GrandFather (Saint) on Jul 25, 2006 at 06:44 UTC

    This sounds like a classic XY Problem. Instead tell us what problem you are trying to solve by using a plethora of "generated" variables.


    DWIM is Perl's answer to Gödel
Re: Creating variables for each array member
by johngg (Canon) on Jul 25, 2006 at 10:10 UTC
    As Zaxo and Corion have already said, you could but you shouldn't. You can achieve the same thing by holding your buttons in a hash with the button name as the key and the widget as the value. The script below does this, the pertinent code is in the arrangeButtons() subroutine.

    The script doesn't actually access the buttons by name to destroy them but it could easily do so with the hash solution. It is just creating and destroying the buttons in bulk while testing algorithms for placing them using the grid().

    I hope this is of use.

    Cheers,

    JohnGG

Re: Creating variables for each array member
by davorg (Chancellor) on Jul 25, 2006 at 11:02 UTC

    There are some questions that are asked so frequently that people have put them in a document called a "FAQ" (for "Frequently Asked Questions") along with their answers in the hope that if the answers are so easily available then people won't have to ask these questions so often.

    For some reason this plan doesn't work very well and people rarely check the FAQ before asking questions. Anyway, this question is answered in the FAQ.

    How can I use a variable as a variable name?

    --
    <http://dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

Re: Creating variables for each array member
by zentara (Cardinal) on Jul 25, 2006 at 13:03 UTC
    Learn to stuff your objects into hashes. Once you get the idea, it makes looping thru them a breeze. Here is a simple example.
    #!/usr/bin/perl use warnings; use Tk; my $mw = tkinit; my %buttonhash; my @array = (0..5); for $i ( @array ) { $buttonhash{$i} = $mw->Button( -text => "Button $i", -command => [\&printme, $i], )->pack(); } my $reconbut = $mw->Button( -text => 'Reconfigure', -command => \&recon, )->pack(); MainLoop; sub printme { print "@_\n"; } sub recon{ foreach my $key (sort keys %buttonhash){ $buttonhash{$key}->configure(-text => 'Button '. ($key + 10)); } }

    I'm not really a human, but I play one on earth. Cogito ergo sum a bum

      In general where you want to cart some context around stuffing disperate objects into a hash is excellent. In the case OP has stated an array is the natural structure.

      Your sample reworked to use an array and to fix the "doesn't print the actual button text" issue becomes:

      #!/usr/bin/perl use warnings; use Tk; my $mw = tkinit; my @buttons; for $i ( 0..5 ) { $buttons[$i] = $mw->Button(-text => "Button $i",)->pack(); $buttons[$i]->configure (-command => [\&printme, $buttons[$i]],); } my $reconbut = $mw->Button(-text => 'Reconfigure', -command => \&recon +,)->pack(); MainLoop; sub printme { print $_[0]->cget (-text) . "\n"; } sub recon{ $buttons[$_]->configure(-text => 'Button '. ($_ + 10)) for 0..$#bu +ttons; }

      OP should note that an important difference between using the hash and an array is that the hash doesn't preserve insertion order (unless you use a little magic) which is why zentara's code used foreach my $key (sort keys %buttonhash) to iterate over the buttons (although the sort isn't actually required in this case) where the array version uses for 0..$#buttons.


      DWIM is Perl's answer to Gödel
        Right. Another minor point I would make, which almost every new "hash-stuffer" runs into, is avoiding the error "can't use a hash ref as a key".

        So for instance in

        for $i ( @array ) { $buttonhash{$i} = $mw->Button( -text => "Button $i", -command => [\&printme, $i], )->pack(); }

        It would be better to write it as

        $buttonhash{$i}{'object'} = $mw->Button(....)
        that way, you can stuff the hash with other data, like
        $buttonhash{$i}{'button_text'} = 'foobar'

        I'm not really a human, but I play one on earth. Cogito ergo sum a bum
Re: Creating variables for each array member
by Moron (Curate) on Jul 25, 2006 at 11:10 UTC
    A container class seems more appropriate than an array, given that you are already working with classes, for example:
    use ButtonJar; my $jar = ButtonJar -> new(); $jar -> add( $but1 );
    package ButtonJar; sub new { my $self = shift; $self = {}; return bless $self; } sub add { # add a button to the "jar" my $self = shift; my $but = shift; $self -> { $but -> id() } = $but; sub remove { # remove a button my $self = shift; my $but = shift; delete $self -> { $but -> id() }; } sub getall ( my $self = shift; return keys %$self; # to return the $widget -> id # or could return values %$self or just %$self # depending on how you want to reference your buttons } 1;

    -M

    Free your mind

      Moron,

      But surely for your suggestion to have any value the Tk widgets would need an ID method, which they don't have. And having created the widgets and 'add'ed them into the container class how do you tell them apart again?

      jdtoronto

        Tk::Widget and scroll down to the section headed $widget->id

        And re 'how do you tell them apart...', I've now added some comments to show that this is just an example -- I would probably use the object reference and therefore store the object reference instead of the id, but it really makes no functional difference. I notice that someone else has suggested code to store them in a hash. In a way that is what I am suggesting, but take a look at the huge reduction in coding requirements when you use a class instead of just a hash.

        -M

        Free your mind