Professional Web Applications Themes

Variable scope in wanted function - PERL Beginners

Greetings All - I am having some difficulty with a module that is using File::Find. The method is below. The idea is to enter this method feeding it a file name and beginning directory and then looking for all occasions of $file_name and push those addresses into a_files. This works fine until I need to use FindPath again during the same session. What I'm finding is that while a_files looses scope within FindPath itself, it does not in ProcessFile. In other words, when I exit FindPath and come back into it later, a_files is an uninitiated array. However when ProcessFile ...

  1. #1

    Default Variable scope in wanted function

    Greetings All -

    I am having some difficulty with a module that is using File::Find. The
    method is below.

    The idea is to enter this method feeding it a file name and beginning
    directory and then looking for all occasions of $file_name and push those
    addresses into a_files. This works fine until I need to use FindPath again
    during the same session. What I'm finding is that while a_files looses
    scope within FindPath itself, it does not in ProcessFile. In other words,
    when I exit FindPath and come back into it later, a_files is an uninitiated
    array. However when ProcessFile is called, a_files has retained the values
    it had from the last call to FindPath.

    Am I making sense?


    sub FindPath
    {
    #- Var Declaration And Initialization
    my ($hr_self, $file_name, $file_path) = _;
    # Array to fill with file paths
    my a_files = ();

    # Search file_path for the file
    find(\&ProcessFile, $file_path);

    #- The Subroutine To Process Files And Directories
    sub ProcessFile
    {if ($_ eq $file_name){push (a_files, $File::Find::name);}}

    # Return the paths found
    return a_files;
    } # end FindPath

    Peace -
    Ron Goral


    Ron Guest

  2. #2

    Default Re: Variable scope in wanted function

    Ron Goral wrote: 

    Yes. But you are apparently running the code without warnings enabled,
    or else Perl would have indicated the reason for this problem.
     

    One possible solution is to move the ProcessFile() function out from
    FindPath(), so the former is no longer a nested sub:

    sub ProcessFile {
    my ($a_files, $file_name) = _;
    push $a_files, $File::Find::name if $_ eq $file_name;
    }

    and call ProcessFile() from FindPath() with arguments:

    find( \&ProcessFile( \a_files, $file_name ), $file_path );

    And last but not least:

    use warnings;

    ;-)

    --
    Gunnar Hjalmarsson
    Email: http://www.gunnar.cc/cgi-bin/contact.pl
    Gunnar Guest

  3. #3

    Default Re: Variable scope in wanted function

    From: Gunnar Hjalmarsson <cc> 
    >
    > Yes. But you are apparently running the code without warnings enabled,
    > or else Perl would have indicated the reason for this problem.

    >
    > One possible solution is to move the ProcessFile() function out from
    > FindPath(), so the former is no longer a nested sub:
    >
    > sub ProcessFile {
    > my ($a_files, $file_name) = _;
    > push $a_files, $File::Find::name if $_ eq $file_name;
    > }
    >
    > and call ProcessFile() from FindPath() with arguments:
    >
    > find( \&ProcessFile( \a_files, $file_name ), $file_path );[/ref]

    You can't do that. You'd have to write it like this:

    find( sub {ProcessFile( \a_files, $file_name )}, $file_path );

    Another option would be to use an unnamed subroutine like this:

    sub FindPath
    {
    #- Var Declaration And Initialization
    my ($hr_self, $file_name, $file_path) = _;
    # Array to fill with file paths
    my a_files = ();

    # Search file_path for the file
    find(sub {
    if ($_ eq $file_name){push (a_files, $File::Find::name);}
    }, $file_path);

    # Return the paths found
    return a_files;
    } # end FindPath


    Or (which might very well be fastest) you'd declare the $file_name
    and a_files outside the FindPath and ProcessFile:

    {
    my ($file_name, a_files);

    sub FindPath
    {
    #- Var Declaration And Initialization
    my ($hr_self, $file_path);
    ($hr_self, $file_name, $file_path) = _;
    # Array to fill with file paths
    a_files = ();

    # Search file_path for the file
    find(\&ProcessFile, $file_path);

    # Return the paths found
    return a_files;
    } # end FindPath

    #- The Subroutine To Process Files And Directories
    sub ProcessFile {
    if ($_ eq $file_name){push (a_files, $File::Find::name);}
    }
    }

    HTH, Jenda
    ===== cz === http://Jenda.Krynicky.cz =====
    When it comes to wine, women and song, wizards are allowed
    to get drunk and croon as much as they like.
    -- Terry Pratchett in Sourcery

    Jenda Guest

  4. #4

    Default RE: Variable scope in wanted function


     
    >
    > Yes. But you are apparently running the code without warnings enabled,
    > or else Perl would have indicated the reason for this problem.

    >
    > One possible solution is to move the ProcessFile() function out from
    > FindPath(), so the former is no longer a nested sub:
    >
    > sub ProcessFile {
    > my ($a_files, $file_name) = _;
    > push $a_files, $File::Find::name if $_ eq $file_name;
    > }
    >
    > and call ProcessFile() from FindPath() with arguments:
    >
    > find( \&ProcessFile( \a_files, $file_name ), $file_path );
    >
    > And last but not least:
    >
    > use warnings;
    >
    > ;-)
    >
    > --
    > Gunnar Hjalmarsson
    > Email: http://www.gunnar.cc/cgi-bin/contact.pl[/ref]

    Actually, I am using warnings. However, in the 'real' code, I have placed
    the the call to 'find' within an eval block so that I can manage the errors.
    Is this why I did not receive any warnings? The difficulties with moving
    ProcessFile out of FindPath is that any return values ProcessFile might have
    are ignored and it can take no arguments (this is from
    http://search.cpan.org/~nwclark/perl-5.8.5/lib/File/Find.pm#The_wanted_funct
    ion).

    I've setting up a "global" variable like $hr_self->{a_files}, where $hr_self
    is an object ref to the module. This requires calling ProcessFile like so:

    find(\$hr_self->ProcessFile, $file_path);
    or
    find(\&ProcessFile($hr_self), $file_path);

    File::Find dies here with the complaint "invalid top directory at
    /usr/lib/perl5/5.6.1/File/Find.pm line 295, line 36." I'm fairly certain
    this is because of the '$hr_self->'. I'm also completely out of ideas for
    this. At least when ProcessFile is defined within FindPath, the only
    variable trouble I had was with a_files.

    There is a light, however. If ProcessFile is actually an anonymous sub and
    called this way:

    my $processfile = sub {if ($_ eq $file_name){push (a_files,
    $File::Find::name);}};

    find(\&$processfile, $file_path);

    There are no errors and a_files is populated (and depopulated) as it should
    be.

    Thanks for taking the time to check this out and to write an answer.


    Ron Guest

  5. #5

    Default Re: Variable scope in wanted function

    Ron Goral wrote: 
    >
    > Actually, I am using warnings. However, in the 'real' code, I have
    > placed the the call to 'find' within an eval block so that I can
    > manage the errors. Is this why I did not receive any warnings?[/ref]

    I get the same warnings also with such an eval block.
     

    No return values does not matter, since my suggestion didn't make use
    of return values from ProcessFile, but the rest does. Jenda showed us
    a way to modify that approach to working code.

    Sorry for posting non-tested code. :(

    <snip>
     

    Yes, that seems to be a nice solution. You can even pass it to find()
    by just saying:

    find( $ProcessFile, $file_path );

    If you haven't already, to get an understanding of what the original
    problem actually was about, you can read the "Variable '%s' will not
    stay shared" section in "perldoc perldiag".

    --
    Gunnar Hjalmarsson
    Email: http://www.gunnar.cc/cgi-bin/contact.pl
    Gunnar Guest

  6. #6

    Default RE: Variable scope in wanted function


     
    > >
    > > Yes. But you are apparently running the code without warnings enabled,
    > > or else Perl would have indicated the reason for this problem.
    > > 
    > >
    > > One possible solution is to move the ProcessFile() function out from
    > > FindPath(), so the former is no longer a nested sub:
    > >
    > > sub ProcessFile {
    > > my ($a_files, $file_name) = _;
    > > push $a_files, $File::Find::name if $_ eq $file_name;
    > > }
    > >
    > > and call ProcessFile() from FindPath() with arguments:
    > >
    > > find( \&ProcessFile( \a_files, $file_name ), $file_path );[/ref]
    >
    > You can't do that. You'd have to write it like this:
    >
    > find( sub {ProcessFile( \a_files, $file_name )}, $file_path );
    >
    > Another option would be to use an unnamed subroutine like this:
    >
    > sub FindPath
    > {
    > #- Var Declaration And Initialization
    > my ($hr_self, $file_name, $file_path) = _;
    > # Array to fill with file paths
    > my a_files = ();
    >
    > # Search file_path for the file
    > find(sub {
    > if ($_ eq $file_name){push (a_files, $File::Find::name);}
    > }, $file_path);
    >
    > # Return the paths found
    > return a_files;
    > } # end FindPath
    >
    >
    > Or (which might very well be fastest) you'd declare the $file_name
    > and a_files outside the FindPath and ProcessFile:
    >
    > {
    > my ($file_name, a_files);
    >
    > sub FindPath
    > {
    > #- Var Declaration And Initialization
    > my ($hr_self, $file_path);
    > ($hr_self, $file_name, $file_path) = _;
    > # Array to fill with file paths
    > a_files = ();
    >
    > # Search file_path for the file
    > find(\&ProcessFile, $file_path);
    >
    > # Return the paths found
    > return a_files;
    > } # end FindPath
    >
    > #- The Subroutine To Process Files And Directories
    > sub ProcessFile {
    > if ($_ eq $file_name){push (a_files, $File::Find::name);}
    > }
    > }
    >
    > HTH, Jenda
    > ===== cz === http://Jenda.Krynicky.cz =====
    > When it comes to wine, women and song, wizards are allowed
    > to get drunk and croon as much as they like.
    > -- Terry Pratchett in Sourcery
    >
    >[/ref]

    Thanks to everyone who replied to this problem.

    I discovered that what I had done, inadvertantly, was created a closure with
    the ProcessFile function. The closure will act on 'my' vars that are
    created outside of its own scope, however, it will retain the values it
    assigned to the var. There is a much better explanation in Perl FAQ 7
    (http://www.perldoc.com/perl5.8.4/pod/perlfaq7.html#What's-a-closure-).

    This is how I ended up solving the issue:

    sub FindPath
    {
    #- Var Declaration And Initialization
    my ($hr_self, $file_name, $file_path) = _;
    #- Array to fill with file paths
    my a_files = ();

    #- The Subroutine To Process Files And Directories
    my $process_file = sub
    {push (a_files, $File::Find::name) if $_ eq $file_name;return;};

    #- Search file_path Looking For This File
    find(\&$process_file, $file_path);

    return a_files;
    } # end FindPath

    Now, the var $process_file is a coderef. While having stumbled on this
    closure business was pretty baffling, I'm glad I did. It's an interesting
    concept that I might could use advantageously in the future.

    Thanks again -
    Ron Goral


    Ron Guest

Similar Threads

  1. PHP variable scope bug in CT
    By lemp555 in forum Macromedia Contribute General Discussion
    Replies: 3
    Last Post: August 18th, 05:45 PM
  2. [PHP-DEV][2] Variable Scope
    By LingWitt@insightbb.com in forum PHP Development
    Replies: 0
    Last Post: August 31st, 01:24 PM
  3. [PHP-DEV][1] Variable Scope
    By LingWitt@insightbb.com in forum PHP Development
    Replies: 0
    Last Post: August 31st, 01:24 PM
  4. [PHP-DEV] Variable Scope
    By LingWitt@insightbb.com in forum PHP Development
    Replies: 18
    Last Post: August 31st, 01:24 PM
  5. Re[2]: [PHP-DEV] Variable Scope
    By Marcus Börger in forum PHP Development
    Replies: 4
    Last Post: August 30th, 06:55 PM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139