http://www.perlmonks.org?node_id=370566

Today I used File::Find for the first time. It worked very nicely for what I wanted to do, the only gripe I had about it is that part of the interface uses global variables and gives the warning "don't touch". For example for the 'wanted' subroutine that is passed to 'find', it is not passed any parameters, it is required to use the global variables   $File::Find::dir,$_, and $File::Find::name .
For my quick script that I was using this wasn't a big deal, but I could see if I was using this module a lot I would want to change the interface a little bit, so the 'wanted' routine actually recieved this information through "@_" instead of through global variables. This is a scenario that I have run into many times, where there is a module that has the functionality I want, but an interface that I don't like. How do you usually handle this situation, do you:
1. Live with the interface
2. Create a wrapper class with a different interface
3. Write a whole new class
4. Something else?

Replies are listed 'Best First'.
Re: When should a wheel be reinvented
by Old_Gray_Bear (Bishop) on Jun 29, 2004 at 18:30 UTC
    At one time or another I have done all of the above. The answer depends on how much time you have.

    If the need is immediate, either live with it or hack up a Q&D wrapper. (Don't forget to make a note of it, though, or the next person to do maintenance on the code will Take Your Name In Vain.) If you have more time (note: I did not say 'spare time'...), drop a note to the module Owner and see if they would be amenable to you adding another interface. Or build an extension module to wrap all of the old module up in a container class and post that to CPAN.

    ----
    I Go Back to Sleep, Now.

    OGB

Re: When should a wheel be reinvented
by perrin (Chancellor) on Jun 29, 2004 at 18:38 UTC

      Of course, what I really would love to see is something that had an API like File::Find::Rule (or File::Finder) but that didn't wrap File::Find.

      Why? Because File::Find gets all the files/directories/etc first, and then starts calling its callback. When dealing with a very large tree, it's memory-inefficient, and you end up waiting forever for the first call to happen. So annoying.

Re: When should a wheel be reinvented
by ihb (Deacon) on Jun 29, 2004 at 18:37 UTC

    I search CPAN to see if anyone else found this an annoyance. If that gives nothing or that other modules aren't good enough in other aspects, I have to consider whether it's a crusial design change (that would make it fit into a pattern I use in the project), if I can live with it, or how big an effort it would be to rewrite it and if I'm good enough on the subject to rewrite an equally good module. The result of that consideration depends on the situation. There's too many circumstances involved that I can't give you a better answer than that. But the first step is always (or should be) to see if anyone has done it for you and evaluate those solutions.

    In the particular case of File::Find there are plenty of other modules that does the same thing with different interfaces.

    ihb

      In the particular case of File::Find there are plenty of other modules that does the same thing with different interfaces.

      Of course, the particular problem in the case of File::Find is that it has been christened by the community as the way to do directory traversal. I know that I've been slammed in the past for mentioning that I wanted to do things in a way that was incompatible with File::Find.

      Also, most of the other ways to do directory traversal are wrappers arround File::Find (File::Finder, File::Find::Rule, for example). All others (that I know of) do it poorly (as well as older versions of File::Find... which are all that work on older perls).

      ------------ :Wq Not an editor command: Wq
Re: When should a wheel be reinvented
by BrowserUk (Pope) on Jun 29, 2004 at 18:44 UTC

    (I think) There's no real reason why the values shouldn't be passed in via @_ in the normal way.

    sub test (&@) { my $code=shift; map $code->( $_, 'other', 'params' ), @_; }; test { print "\$_ = $_ \@_ = '@_'"; } 1 .. 10; $_ = 1 @_ = '1 other params' $_ = 2 @_ = '2 other params' $_ = 3 @_ = '3 other params' $_ = 4 @_ = '4 other params' $_ = 5 @_ = '5 other params' $_ = 6 @_ = '6 other params' $_ = 7 @_ = '7 other params' $_ = 8 @_ = '8 other params' $_ = 9 @_ = '9 other params' $_ = 10 @_ = '10 other params'

    (I think) The same could be done for File::Find and other subs that take anon. blocks/subs as args--sort blocks, List::Util functions etc.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    "Memory, processor, disk in that order on the hardware side. Algorithm, algoritm, algorithm on the code side." - tachyon

      Here is a patch for File::Find so that it passes args and looks after $_.

      cheers

      tachyon

Re: When should a wheel be reinvented
by etcshadow (Priest) on Jun 29, 2004 at 18:46 UTC
    It's a good question... sometimes wheels do have to be reinvented. For the record, I've vented on the interface to File::Find a few times before.

    That being said, people probably spend too much time reinventing the wheel. This isn't so bad if you're only doing it for practice... but CPAN is pretty cluttered with lots of modules that all do largely the same thing. It's probably only worthwhile releasing it to the community if it adds some significant value over what was there before.

    ------------ :Wq Not an editor command: Wq
Re: When should a wheel be reinvented
by leriksen (Curate) on Jun 30, 2004 at 01:30 UTC
    Man who reinvent wheel knows awful lot about making wheels.

    So treat reinvention as a learning exercise.

    I'm planning to 'reinvent' a Huffman coding module - I'll learn heaps about the algorithm, and there is plenty of scope for 'improving' it via speed improvement with C and XS, different dictionaries of symbol frequencies, different style interfaces(oo/functional/tied), Apache modules to acts as a deflate/inflate filters, SOAP/.NET interfaces, etc etc

    In fact one could use a problem like this to compare the subjective ease/power qualities of a language - how hard is it to do in Perl/Python/LISP/C/.NET/Ruby/BF etc

    +++++++++++++++++
    #!/usr/bin/perl
    use warnings;use strict;use brain;

      May I direct you to Red Perl Part I?

      BTW, Huffman coding is a lousy (not lossy, lousy) compression technique.

Re: When should a wheel be reinvented
by EdwardG (Vicar) on Jun 30, 2004 at 07:52 UTC

    Personally I find it satisfying to have a go at reinventing every wheel, time permitting, and then, at least, when I finally use the established wheel, I have some insight into the issues and challenges of the problem. This means I can better appreciate how inferior my approach was :-) and how superior (or sometimes not) is the shrink wrapped solution.

     

Re: When should a wheel be reinvented
by tachyon (Chancellor) on Jun 30, 2004 at 03:20 UTC

    The patch is pretty trivial (minimal testing but don't see why it should not be stable). The value of $_ is saved and restored so you can change/use it in &wanted with impunity. Note as we are passing 3 values to the &wanted every time there will be a slowdown but this is probably (speculation) trivial compared to iterating over the directory tree.

    $ diff Find.pm FindPatch.pm 1c1 < package File::Find; --- > package File::FindPatch; 394c394 < { &$wanted_callback }; # protect against wild "next" --- > { my $save=$_; &$wanted_callback($save,$name,$dir); $_=$ +save }; # protect against wild "next" 450c450 < { &$wanted_callback }; # protect against wild "next" --- > { my $save=$_; &$wanted_callback($save,$name,$dir); $_=$ +save }; # protect against wild "next" 495c495 < { &$wanted_callback }; # protect against wild "next" --- > { my $save=$_; &$wanted_callback($save,$name,$dir); $_ +=$save }; # protect against wild "next" 519c519 < { &$wanted_callback }; # protect against wild +"next" --- > { my $save=$_; &$wanted_callback($save,$name,$ +dir); $_=$save }; # protect against wild "next" 525c525 < { &$wanted_callback }; # protect against wild "nex +t" --- > { my $save=$_; &$wanted_callback($save,$name,$dir) +; $_=$save }; # protect against wild "next" $

    cheers

    tachyon

      All of your my $save=$_; ... $_=$saves can be replaced by local $_=$_; ...


      Warning: Unless otherwise stated, code is untested. Do not use without understanding. Code is posted in the hopes it is useful, but without warranty. All copyrights are relinquished into the public domain unless otherwise stated. I am not an angel. I am capable of error, and err on a fairly regular basis. If I made a mistake, please let me know (such as by replying to this node).

        Good point, not that it makes much practical difference.

Re: When should a wheel be reinvented
by Anonymous Monk on Jun 29, 2004 at 21:20 UTC
    Reinventing the wheel is fine if what you really need is a tire.
Re: When should a wheel be reinvented
by exussum0 (Vicar) on Jun 30, 2004 at 16:56 UTC
    In general...

    If it does what you want but can't modify it, you wrap it.
    If it's a blackbox, you rewrite it if you have the resources. Blackboxes are dangerous.
    If you have the source, you fix it unless it takes too long.

    -s

    Bart: God, Schmod. I want my monkey-man.

      You cannot generally wrap a callback interface with a looping interface unless you have continuations, co-routines, or some other similar construct. Perl does not. (Well, there is a module that adds it, but I'm not sure what issues it has. Certainly it isn't a built-in feature.)

      Whether it is good for a language to have continuations is another debate, and there are top-notch people who'll argue both sides of that choice.

      Regardless, Perl 6 will have continuations.

        Here, here. See this node for some further discussion (which, in fact, also happens to mention File::Find and it's callback-based interface).
        ------------ :Wq Not an editor command: Wq