> -----Original Message-----
> From: Jenda Krynicky [mailto:[EMAIL PROTECTED]
> Sent: Monday, October 11, 2004 10:39 AM
> To: [EMAIL PROTECTED]
> Subject: Re: Variable scope in wanted function
>
>
> From: Gunnar Hjalmarsson <[EMAIL PROTECTED]>
> > Ron Goral wrote:
> > > 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?
> >
> > Yes. But you are apparently running the code without warnings enabled,
> > or else Perl would have indicated the reason for this problem.
> >
> > > 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
> >
> > 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( [EMAIL PROTECTED], $file_name ), $file_path );
>
> You can't do that. You'd have to write it like this:
>
>       find( sub {ProcessFile( [EMAIL PROTECTED], $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
> ===== [EMAIL PROTECTED] === 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
>
>

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



-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
<http://learn.perl.org/> <http://learn.perl.org/first-response>


Reply via email to