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

Beware this question may be pointless or basic but it is bugging me. What is the differance between
my @foo; my %bar; my $yuk; and my @foo=(); my %bar=(); my $yuk={};
Does pre declaring variables before you use them have any memory/performance benefit for the interpreter by providing type information. I know in other strongly typed languages you should always declare the type of your variable but does it matter in perl or am I doing it by prepending @ or % or $.

Also is putting a 'my' call inside a loop to clear the variable advisable?

Replies are listed 'Best First'.
Re: Predeclaration
by broquaint (Abbot) on Jul 16, 2002 at 11:04 UTC
    Does pre declaring variables before you use them have any memory/performance benefit for the interpreter by providing type information.
    Essentially no. There are several reasons for this one of which is that perl isn't a strongly typed language so the compiler isn't designed to take advantage of 'type hints'. In fact it is every so slightly quicker to *not* predeclare your variables in terms of execution speed as it increases the amount of operations to be performed
    use Benchmark qw(cmpthese); ## take the results with a grain of salt, mmmkay? cmpthese(-15, { predeclare => sub { my $x = {}; $x->{foo} = "bar" x 20 }, nodeclare => sub { my $x; $x->{foo} = "bar" x 20 } }); __output__ Benchmark: running nodeclare, predeclare, each for at least 15 CPU sec +onds... nodeclare: 24 wallclock secs (15.33 usr + 0.00 sys = 15.33 CPU) @ 11 +0465.75/s (n=1693440) predeclare: 18 wallclock secs (15.58 usr + 0.02 sys = 15.60 CPU) @ 89 +620.83/s (n=1398085) Rate predeclare nodeclare predeclare 89621/s -- -19% nodeclare 110466/s 23% --
    So as you can see the sub *without* the anonymous hash assignment was ever so slightly faster, but I'd say the difference is fairly negligible.
    I know in other strongly typed languages you should always declare the type of your variable but does it matter in perl or am I doing it by prepending @ or % or $.
    There are only really two types in perl and they are scalars and lists and everything else from there on out is an abstraction. For more information on strongly-typed languages and perl see. Ovid's Griping about Typing, and for info about data types in perl see the perldata manpage.
    Also is putting a 'my' call inside a loop to clear the variable advisable?
    I think you may have a misunderstanding of what function my() performs. Declaring a variable with my() will create a new variable in the current lexical scope, that's all. So you're not 'clearing' the variable you're just creating a new variable in the current lexical scope e.g
    my $foo = "a string"; print "\$foo is $foo\n"; ## this $foo only lasts to the end of the for loop scope for my $foo (1..3) { print "\$foo is $foo\n"; } print "\$foo is $foo\n"; __output__ $foo is a string $foo is 1 $foo is 2 $foo is 3 $foo is a string

    HTH

    _________
    broquaint

      Thanks broquaint guess I'll stop doing it then. My question now is why does anyone bother to predeclare if it has no effect or an adverse effect.

      I suppose it must just be for improved readability and to help the stongly typed converts

        People generally predeclare with my to assist with error-checking. If you add the pragma use strict; to the top of your program, all variables have to be declared with my or our before they're used. This helps eliminate errors due to variable name typos.

        For example:

        use strict; my $typo; $tuypo = "Here's some data: $data"; print $typo;
        will produce an error.

Re: Predeclaration
by Abigail-II (Bishop) on Jul 16, 2002 at 12:42 UTC
    There is hardly any difference between
    my @foo; my %bar;
    and
    my @foo = (); my %bar = ();
    Both will declare the variables at compile time, and assign an empty list to them at run time. Using Devel::Peek shows there is no difference.
    #!/usr/bin/perl use strict; use warnings 'all'; use Devel::Peek; my @foo_1; my @foo_2 = (); my %bar_1; my %bar_2 = (); print STDERR "\@foo_1:\n"; Dump (\@foo_1); print STDERR "\@foo_2:\n"; Dump (\@foo_2); print STDERR "\%bar_1:\n"; Dump (\%bar_1); print STDERR "\%bar_2:\n"; Dump (\%bar_2); __END__
    @foo_1:
    SV = RV(0x81584b4) at 0x814490c
      REFCNT = 1
      FLAGS = (TEMP,ROK)
      RV = 0x814ead4
      SV = PVAV(0x8145e5c) at 0x814ead4
        REFCNT = 2
        FLAGS = (PADBUSY,PADMY)
        IV = 0
        NV = 0
        ARRAY = 0x0
        FILL = -1
        MAX = -1
        ARYLEN = 0x0
        FLAGS = (REAL)
    @foo_2:   
    SV = RV(0x81584b4) at 0x814490c
      REFCNT = 1
      FLAGS = (TEMP,ROK)
      RV = 0x814eaec
      SV = PVAV(0x8145e28) at 0x814eaec
        REFCNT = 2 
        FLAGS = (PADBUSY,PADMY)
        IV = 0
        NV = 0
        ARRAY = 0x0
        FILL = -1
        MAX = -1   
        ARYLEN = 0x0
        FLAGS = (REAL)
    %bar_1:
    SV = RV(0x81584b4) at 0x814490c
      REFCNT = 1
      FLAGS = (TEMP,ROK)
      RV = 0x814eb10
      SV = PVHV(0x81535b8) at 0x814eb10
        REFCNT = 2  
        FLAGS = (PADBUSY,PADMY,SHAREKEYS)
        IV = 0
        NV = 0
        ARRAY = 0x0
        KEYS = 0
        FILL = 0   
        MAX = 7  
        RITER = -1
        EITER = 0x0 
    %bar_2:
    SV = RV(0x81584b4) at 0x814490c
      REFCNT = 1
      FLAGS = (TEMP,ROK)
      RV = 0x814eba0
      SV = PVHV(0x81535f0) at 0x814eba0
        REFCNT = 2
        FLAGS = (PADBUSY,PADMY,SHAREKEYS)
        IV = 0
        NV = 0
        ARRAY = 0x0
        KEYS = 0   
        FILL = 0 
        MAX = 7    
        RITER = -1  
        EITER = 0x0   
    
    However, there is a big difference between
    my $yuk;
    and
    my $yuk = {};
    The former assigns an undefined value to $yuk, while the latter assigns a reference to an anonymous hash to $yuk.

    Devel::Peek will show the difference:

    #!/usr/bin/perl use strict; use warnings 'all'; use Devel::Peek; my $yuk_1; my $yuk_2 = {}; print STDERR "\$yuk_1:\n"; Dump ($yuk_1); print STDERR "\$yuk_2:\n"; Dump ($yuk_2);
    $yuk_1:
    SV = NULL(0x0) at 0x814eacc
      REFCNT = 1
      FLAGS = (PADBUSY,PADMY)
    $yuk_2:
    SV = RV(0x8158458) at 0x814eae4
      REFCNT = 1
      FLAGS = (PADBUSY,PADMY,ROK)
      RV = 0x814490c
      SV = PVHV(0x8153550) at 0x814490c
        REFCNT = 1
        FLAGS = (SHAREKEYS)
        IV = 0
        NV = 0
        ARRAY = 0x0
        KEYS = 0
        FILL = 0   
        MAX = 7
        RITER = -1
        EITER = 0x0
    

    Abigail

Re: Predeclaration
by jmcnamara (Monsignor) on Jul 16, 2002 at 11:31 UTC

    The my() declares the scope to the varaible and not the type. The type doesn't change.* In your example the variables will remain an array, a hash and a scalar no matter what you put into them.

    Perhaps what you are really asking is whether there is any advantage of initialising variables like this. As far as I know there is no substantive difference between the two of these:

    my @array; my @array = ();
    However, you can gain some performance increase by pre-extending an array or a hash if you know what size it is likely to be:
    my @array; $#array = 99; my %hash; keys %hash = 100;

    --
    John.

    * Leaving arguments about bless() aside.

Re: Predeclaration
by flounder99 (Friar) on Jul 16, 2002 at 14:43 UTC
    I learned something today. I thought that with my @x; @x would be undefined but with my @x = (); @x would be a defined but empty list. I guess I was wrong. Here is the experiment I ran. I
    my @x; print 'my @x;',"\n"; &checkdef; @x = (); print '@x = ();',"\n"; &checkdef; @x = (1); print '@x = (1);',"\n"; &checkdef; @x = (); print '@x = ();',"\n"; &checkdef; undef @x; print 'undef @x;',"\n"; &checkdef; @x = (); print '@x = ();',"\n"; &checkdef; sub checkdef { if (defined (@x)) { print "\@x is defined\n" } else { print "\@x is undefined\n" } } __OUTPUT__ my @x; @x is undefined @x = (); @x is undefined @x = (1); @x is defined @x = (); @x is defined undef @x; @x is undefined @x = (); @x is undefined

    Is anyone else surprised by the results?

    --

    flounder

      Is anyone else surprised by the results?
      People who read the manual pages will not be surprised. From the manual page about defined:
                     Use of "defined" on aggregates (hashes and arrays)
                     is deprecated.  It used to report whether memory
                     for that aggregate has ever been allocated.  This
                     behavior may disappear in future versions of Perl.
                     You should instead use a simple test for size:
      
                         if (@an_array) { print "has array elements\n" }
                         if (%a_hash)   { print "has hash members\n"   }
      

      Abigail

        Damn documentation! Another case of what I think it does vs. what it really does (and is documented) DWIMing has me spoiled. I think perl's ability to read my mind needs improving! Larry needs to take some lessons from Miss Cleo! (Or at least the acress who plays her)

        --

        flounder

        ps. For those of you outside the USA (or who never turned on a TV after 11pm in the US) Miss Cleo was a (so called) psychic with a bad fake Jamacan accent who pushed a psychic hotline. The actress who played her recently appeared in court and admitted she was not Jamacan during a fraud investigation.

Re: Predeclaration
by cybear (Monk) on Jul 16, 2002 at 13:46 UTC

    Background: If you call the value of a segment of memory,
    I'm thinking C/C++ here, then the value returned is the
    value that already exitst in that memory space. For example:
    if 12345 existed at a specific segment of memory that was
    then assigned to $var, the value of $var would be 12345.
    Unless you predeclare that $var is to be a specific value
    That is a well known security problem, I believe that is
    how stack exploites work.

    Abigail says that the variable is assigned an empty list
    either way you choose to assign it (my $var or my $var = ()).

    If that is true then there should be no security differences
    between either way. Sound correct?

      Perl isn't C, nor C++. In pure Perl there is absolutely no way of directly accessing the content of the (virtual) memory. There are no pointers in Perl - just references. You cannot take an integer, and treat it like a pointer or a reference. You cannot add something to a reference and get a new reference.

      Abigail

        In pure Perl there is absolutely no way of directly accessing the content of the (virtual) memory... You cannot take an integer, and treat it like a pointer or a reference.

        It is impossible with pure Perl and no XS modules. But Devel::Pointer can turn Perl code into C pointers nightmare :)

        --
        Ilya Martynov (http://martynov.org/)