Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine

Re (tilly) 1: Why I hate File::Find and how I (hope I) fixed it

by tilly (Archbishop)
on Aug 30, 2001 at 18:11 UTC ( [id://109079] : note . print w/replies, xml ) Need Help??

in reply to Why I hate File::Find and how I (hope I) fixed it

In fact you have hit on the classic way that you extend a functional system. Instead of passing around more information or creating global data, just move that action into creating a closure which binds the arguments up front for later use.

For an example with many of these closures running around in parallel, see Re (tilly) 1: 5x5 Puzzle. (Look specifically at ret_toggle_square.) And a more general form of your make_wanted function would be:

# Takes an anon function and a list of arguments. Returns # a closure which will call the anon function with those # arguments prepended to the argument list. sub bind_args { my ($sub, @args) = @_; return sub {$sub->(@args, @_);}; }

Replies are listed 'Best First'.
Generating similar functions in unrelated objects
by t'mo (Pilgrim) on Aug 31, 2001 at 02:03 UTC

    Suppose you wanted to do something like this to a family of related objects. How would you assign the anonymous function to be a method of each class? (I can do that trick in JavaScript using ObjectName.prototpye.methodName, but how would I do that in Perl?)

    For example, what I would like to do is:

    ... sub ObjectToString { my $name = shift; return sub { my $s = $name . $self->getParametersAndValues(); return $s; } } ... package Fu; sub toString = ObjectToString("Fu"); ... package Bar; sub toString = ObjectToString("Bar"); ... package Baz; sub toString = ObjectToString("Baz"); ...

    Then I would use it like this:

    my ($foo, $bar, $baz); $foo = Fu->new(); # do stuff with foo... print $foo->toString(); $bar = Bar->new(); # do stuff with bar... print $bar->toString(); ...

    The obvious answer here is to use Inheritance™, but what if, for some reason, I don't want to use inheritance? Can I still accomplish what I want to?

      You would want to do a typeglob assignment. If you assign an anonymous function to a typeglob, you define that function. Like this:
      package Stringify; sub objectToString { my $name = shift; return sub { $name . (shift)->getParametersAndValues(); }; } # Time passes package Fu; *toString = Stringify::objectToString("Fu");
      But I should note that you can make this nicer with overload and an autogenerated method. For instance:
      package Stringify; use strict; use Carp; sub import { my $pkg = caller(); my $code = qq( # A trick for custom error reporting - see perlsyn. \n# line 1 "'Autogenerated for $pkg by Stringify'" package $pkg; use overload '""' => sub { __PACKAGE__ . (shift)->getParametersAndValues(); }; ); eval($code); if ($@) { confess("Cannot autogenerate stringification for package '$pkg': $ +@ The code is:\n$code"); } } 1;
      would allow you to simply:
      package Fu; use Stringify; # Use objects as strings, and they stringify
      If you want you could create an autogenerated function called toString and pass a reference to that function to overload.

        You know what happened, don't you? Just as I was leaving the building, not more than five minutes after I asked the question, the answer came to me: symbol table. :-)

        The import approach is interesting. It gives me more food for thought, especially in relation to this question I asked about writing your own import. Thanks.