Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

The weirdest problem with undef

by insaniac (Friar)
on Dec 22, 2004 at 09:52 UTC ( [id://416731]=perlquestion: print w/replies, xml ) Need Help??

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

sisters, bwothers,

Like the title says, undef is giving me horrible nightmares all of a sudden. I have two variables which I use in a for loop. At the end of that loop, I undef two variables, which are created at the beginning of the loop. Now, in one cycle, the two variables were not empty et al, and contained data from a previous loop... which of course caused lots of evil ;-)

my code looks something like this:

for my $mode (@probe_modes) { my (@source,@destination); create_map_file $mode; get_elements; # @source and @destination are filled here scan_matrix $mode; undef(@source); undef(@destination); }

I'm sure it's the undef that's causing the problem, because the first two subroutines should first check if the arrays need to be filled, and one will actually fill. The one that's checking reports that it's not going to fill (and it doesn't, i checked) and the second one says it's not filling, but there's data in the array of the previous loop.

I'm using:

This is perl, v5.6.1 built for sun4-solaris-64int (with 48 registered patches, see perl -V for more detail) Summary of my perl5 (revision 5.0 version 6 subversion 1) configuratio +n: Platform: osname=solaris, osvers=2.9, archname=sun4-solaris-64int uname='sunos localhost 5.9 sun4u sparc sunw,ultra-1' config_args='' hint=recommended, useposix=true, d_sigaction=define usethreads=undef use5005threads=undef useithreads=undef usemultipl +icity=undef useperlio=undef d_sfio=undef uselargefiles=define usesocks=undef use64bitint=define use64bitall=undef uselongdouble=undef Compiler: cc='cc', ccflags ='-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64', optimize='-xO3 -xdepend', cppflags='' ccversion='Sun WorkShop', gccversion='', gccosandvers='' intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=87654321 d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=1 +6 ivtype='long long', ivsize=8, nvtype='double', nvsize=8, Off_t='of +f_t', lseeksize=8 alignbytes=8, usemymalloc=n, prototype=define Linker and Libraries: ld='cc', ldflags ='' libpth=/lib /usr/lib /usr/ccs/lib libs=-lsocket -lnsl -ldl -lm -lc perllibs=-lsocket -lnsl -ldl -lm -lc libc=/lib/libc.so, so=so, useshrplib=true, libperl=libperl.so Dynamic Linking: dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-R /usr/ +perl5/5.6.1/lib/sun4-solaris-64int/CORE' cccdlflags='-KPIC', lddlflags='-G'
Thanks !
--
to ask a question is a moment of shame
to remain ignorant is a lifelong shame

Replies are listed 'Best First'.
Re: The weirdest problem with undef
by davorg (Chancellor) on Dec 22, 2004 at 10:09 UTC

    As others have said, it looks like you're probably accessing two different sets of variables called @source and @destination. One is the lexical set that you are creating with the "my" call at the start of the loop and the other is the package variable set that you are setting in the "get_elements" call.

    The two best pieces of advice that I can give you are:

    1. Stop relying on side-effects to populate global variables
    2. Turn on "use strict" and "use warnings" so you can see where you are unwittingly using package variables
    --
    <http://www.dave.org.uk>

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

Re: The weirdest problem with undef
by dave_the_m (Monsignor) on Dec 22, 2004 at 10:01 UTC
    Your code can't possibly be doing what you think it's doing. my variables are lexically scoped, which means they can't be seen outside the block of code they are delcared in. Thus, get_elements can't possibly be filling the arrays

    Dave.

      believe me: they get filled. the really get filled, because 99% of the time the scripts works perfectly.
      --
      to ask a question is a moment of shame
      to remain ignorant is a lifelong shame

        I assume you're saying that because you're accessing the data again in "scan_matrix". So here's what's really happening.

        1. Each time round the loop new lexical variables are created by the "my" call.
        2. You then call "get_elements" which puts data into the _package_ variables called @source and @destination, _not_ the lexical variables that you have created.
        3. You then call "scan_matrix" which also accesses the _package_ variable versions.
        4. You then use "undef" in your main loop which effects the _lexical_ versions of the variables.
        5. The loop ends and your lexical variables go out of scope and are destroyed. The package variables, however, still exist and still contain the data that "get_elements" put in them.
        6. The loop executes again and the process repeats.
        --
        <http://www.dave.org.uk>

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

Re: The weirdest problem with undef
by sasikumar (Monk) on Dec 22, 2004 at 11:05 UTC
    Hi

    Its always better to use strict before u start a perl program. Most of the times the problem comes because we are not clear of the scoping of the perl variables. Better to use strict.

    In your case using strict will solve all the problems that you have.

    Thanks
    Sasi kumar

      yeah, but like i said in a previous reply: i didnt and i explained why... bear with me these beginner mistakes, ok?
      btw: strict will _show_ the problems i have, not solve :-p i will have to do the solving part, if i'm smart enough..

      --
      to ask a question is a moment of shame
      to remain ignorant is a lifelong shame
Re: The weirdest problem with undef
by steves (Curate) on Dec 22, 2004 at 10:03 UTC

    How is get_elements filling @source and @destination if they're not being passed to it and they're lexical variables with visibility only in your loop?

    It might help to see more of the code.

Re: The weirdest problem with undef
by dirac (Beadle) on Dec 22, 2004 at 15:19 UTC
    ... and if you try with:
    for my $mode (@probe_modes) {
       local (@source,@destination);
       create_map_file $mode;
       get_elements; # @source and @destination are filled here
       scan_matrix $mode;
       @source =();
       @destination =();
    }
    
      :-D you're about to be spanked! read previous replies above...
      --
      to ask a question is a moment of shame
      to remain ignorant is a lifelong shame
      Which is a quick hack the OP indeed had already found himself. Still it is nothing but byzantine logic to avoid what parameter passing is exactly for.

      Ciao ciao!

Re: The weirdest problem with undef
by saberworks (Curate) on Dec 22, 2004 at 18:20 UTC
    In this case your best bet would be to declare my (@array1, @array2) before the for loop if you want them to be available to your subroutines.

    You are not having a problem with undef, you are having a problem variable scoping.

    As others have mentioned, you should be using strict - you said it won't help you solve the problem, but how can you solve the problem when you clearly don't understand what the problem is? Using strict will help you figure out what the problem is so you can at least look in the right direction.

    Here's what I used to test your code:
    #!/usr/bin/perl use strict; foreach my $item ('top', 'heavy', 'fool') { my (@array1, @array2); a_function($item); print "@array1\n"; print "@array2\n"; } sub a_function { my $item = shift; push @array1, 'crap'; push @array2, 'dumb'; }
    This gave me errors like this:
    Global symbol "@array1" requires explicit package name at ./test_loop. +pl line 18. Global symbol "@array2" requires explicit package name at ./test_loop. +pl line 19. Execution of ./test_loop.pl aborted due to compilation errors.
    This clearly tells me that the subroutine is looking for global variables. Declaring them as my inside a loop doesn't create global variables. So moving them to the top, like this, works fine:
    ... my (@array1, @array2); foreach my $item ('top', 'heavy', 'fool') { ...
      ah thanks!
      this was a really cool answer, learned much from it. like: test your code in smaller in pieces if you have a problem. i always seem to write too much at once, leaving these error hard to find. but like i really really realy learned today: _always_ use strict; and use warnings;.

      again: many thanks to everybody who replied and devoted me. many new insights were given and i developed -i think- a new coding style. i can't say this enough: thanks!

      --
      to ask a question is a moment of shame
      to remain ignorant is a lifelong shame
      What if the subroutines had been exported from another package?
      In this case your best bet would be to declare my (@array1, @array2) before the for loop if you want them to be available to your subroutines.

      [SNIP]

      This clearly tells me that the subroutine is looking for global variables. Declaring them as my inside a loop doesn't create global variables. So moving them to the top, like this, works fine:

      OTOH this suggestion, in this form may contribute to suggest the OP to declare all of his own variables at the top of his scripts, which is indeed a bad habit many newbies have, and goes against proper scoping of variables.

      I do use stuff like

      { my $var; sub bus { $var++; } }
      myself, occasionally. But not as an alternative to parameter passing...

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://416731]
Approved by zejames
Front-paged by dragonchild
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (2)
As of 2024-04-19 21:15 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found