Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister

Generating similar functions in unrelated objects

by t'mo (Pilgrim)
on Aug 31, 2001 at 02:03 UTC ( [id://109219] : note . print w/replies, xml ) Need Help??

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

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?

Replies are listed 'Best First'.
Re (tilly) 3: Generating similar functions in unrelated objects
by tilly (Archbishop) on Aug 31, 2001 at 07:25 UTC
    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.

        Are custom imports a good idea?

        Can I say it depends?

        Most of what I was saying about AUTOLOAD at Re (tilly) 4: Perl and Objects, how do you resolve the two? applies to custom imports as well. A custom import is like a very good sword without a hilt. It can cut really well, but you need to be very cautious before using it.

        My rule of thumb is this. If my custom import could be done with Exporter, I don't use it. If it makes for a significantly improved interface and works very differently, then I will consider it. But if I won't actually use it unless I am going to make it a meme in the body of code that I am working on. It doesn't matter how nice each customized rule is, a million and one customized high-level interfaces is unmaintainable.

        Or, to put it a different way, It is OK to be clever, but only one person should be being clever at a time.