Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??

Did you:

grep DONE: File/Find.pm

before you wrote this code? Do you do that for every label you have ever used this way each time you upgrade File::Find? I'd have more sympathy for going against the first paragraph of "perldoc -f goto"1 if Perl supported the following syntax:

File::Find::find( sub { ... goto My::Package::FOUND ... } ... ); My::Package::FOUND: ....

Does that give you a better feel why some people are not in favor of such a practice?

I suspect that using last to exit a sub generates a warning because it is widely considered a bad practice and last is used enough that accidentally using it to exit a subroutine appeared on the radar. So the warning for last and not for goto has more to do with last being seen as useful and used while goto is not. In particular, the lack of a warning is not an indication that the practice is not seen as a bad one (sorry, I wanted one more negation in there but I grew tired).

I shy aware from using things that the documentation tells me that I shouldn't. Those are the things that get "fixed" to no longer work or that aren't well tested and so nobody notices when they break and so bugs in them survive into "stable" releases.

I shy aware from practices that break just because someone else somewhere also came up with "DONE" for their label name.

But I do see the appeal of such simple and clear code (once the reader gets over the shock of using goto to jump out of a possibly large number of subroutine calls, that is).

BTW, my solution for this problem would probably be to spend less time rolling a dozen-line replacement for File::Find then I'd have to spend searching the File::Find docs to see if it supported a "thanks, I'm done" feature. The classic gotchas are well known to me2 (as well as the failings of File::Find that have caused me grief repeatedly over the many years when I've been unfortunate enough to try to use it or try to use something that used it).

Here, an example I threw together in a couple of minutes:

BEGIN { my( $dot, $up )= ( File::Spec->curdir(), File::Spec->updir() ); sub SearchDirs { my( $path, $subdir )= @_; $path= File::Spec->catdir( $path, $subdir ); chdir $subdir or die "Can't chdir, $path: $!\n"; opendir D, $dot or die "Can't opendir, $path: $!\n"; my @files= grep $_ ne $dot && $_ ne $up, readdir D; closedir D; for( @files ) { my $recurse= ! -l $_ && -d _; # ... SearchDirs( $path, $_ ) if $recurse; } chdir $up or die "Can't chdir .. from $path: $!\n"; } }

Using the above would mean that I at least wouldn't have to worry about "goto DONE;" suddenly not working because I upgraded File::Find.

Just for fun, let's avoid that whole problem and make return work by eliminating the recursion:

#!/usr/bin/perl -w use strict; use File::Spec; # Globals: my( $FiNode, $FnLinks, @Found ); Main( @ARGV ); exit( 0 ); BEGIN { my( $dot, $up )= ( File::Spec->curdir(), File::Spec->updir() ); sub SearchDirs { my( $path )= @_; my @depth= "."; my @todo= ( ".", $path ); while( @todo ) { my $path= shift @todo; my $subdir= shift @todo; while( $path ne $depth[-1] ) { chdir $up or die "Can't chdir .. from $depth[-1]: $ +!\n"; pop @depth; } $path= File::Spec->catdir( $path, $subdir ); push @depth, $path; chdir $subdir or die "Can't chdir, $path: $!\n"; opendir D, $dot or die "Can't opendir, $path: $!\n"; my @files= grep $_ ne $dot && $_ ne $up, readdir D; closedir D; for( @files ) { push @todo, $path, $_ if ! -l $_ && -d _; if( $FiNode == ( lstat _ )[1] ) { push @Found, File::Spec->catfile( $path, $_ ); return if --$FnLinks < 1; } } } } } sub Main { die "Usage: file dir\n" if 2 != @_; my( $fpath, $dir )= @_; ( $FiNode, $FnLinks )= ( lstat $fpath )[1,3]; if( 1 == $FnLinks ) { print $fpath, $/; } else { SearchDirs( $dir ); print $_, $/ for @Found; } }

It even works. (:

- tye        

1 Quote: It can be used to go almost anywhere else within the dynamic scope, including out of subroutines, but it's usually better to use some other construct such as "last" or "die".

2 Such as:

  1. Either use chdir and opendir on File::Spec->curdir() or prepend the path before using stat-like operations
  2. Skip File::Spec->curdir() and ->updir() or you'll loop forever
  3. Don't recurse into symbolic links (or keep a hash of where you've been or just assert that circular links cause infinite loops)


In reply to Re^2: aborting File::Find::find (gotchas) by tye
in thread aborting File::Find::find by marvell

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

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

    No recent polls found