PetaMem has asked for the wisdom of the Perl Monks concerning the following question:

Hello and welcome at the most ... ehm ... simple pontiff cooking question of this decade:

What do we need? We need a simple iterator:

sub iterate { my $code = shift; my $back = TRUE; for(@_) { if(&$code($_) == FALSE) { $back = FALSE; } } return $back; }
a simple call to this iterator:
&iterate(\&attach,@param);
Yeah! This works. Great. No surprises here.

And now some unfortunate OO efforts - such as making attach the method of an object.

my $rep = Module->new();
And then

we try pitifully to reference this method:

&iterate($rep->attach(),@param); # ?? No &iterate(\$rep->attach(),@param); # ?? Noooo &iterate(\{$rep->attach()},@param); # ?? Hehe...
Ok. So questions. Howto? Bad design? (Well the iteration is fairly generic and doesn't hurt any encapsulation). The camel book desn`t help here much, it just states "be nice". Damians OO book didn't mention it (at least I didn't find it).

Bye
 PetaMem

Replies are listed 'Best First'.
Re: Referencing methods
by dragonchild (Archbishop) on May 08, 2003 at 15:43 UTC
    Heh. It's simpler than you think.
    sub iterate_with_obj my $obj = shift; my $method = shift; my $back = TRUE; for(@_) { if($obj->$method($_) == FALSE) { $back = FALSE; } } return $back; } iterate_with_obj($rep, 'attach', @param);
    This works because methods are bound at run-time. :-)

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Re: Referencing methods
by artist (Parson) on May 08, 2003 at 15:48 UTC
Re: Referencing methods
by hardburn (Abbot) on May 08, 2003 at 15:45 UTC

    Pass the object in only, not the subroutine name. Force all objects that are passed in to have a certain method name (which you can check with $obj->can('method_name') which you then call. If you need a single sub that can handle either an object OR a subreferance, just check the output of ref() and mix in some DWIM.

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    Note: All code is untested, unless otherwise stated

Re: Referencing methods
by Thelonius (Priest) on May 08, 2003 at 15:48 UTC
    I believe an anonymous sub would work:
    &iterate(sub { $rep->attach() },@param);
    Untested, of course.
      That's great except it doesn't pass the parameters down. So perhaps this instead:

      iterate(sub { $rep->attach(@_) }, @param);

      Also, you may wish to give iterate an appropriate prototype, making the sub keyword unnecessary:

      sub iterate (&@); iterate { $rep->attach(@_) }, @param;

      Share & Enjoy!

          -- Chip Salzenberg, Free-Floating Agent of Chaos

Re: Referencing methods
by broquaint (Abbot) on May 08, 2003 at 15:48 UTC
    Unfortunately you can't create a reference to an object method due to the fact that calling an object method is really just dereferencing the object with some blessed magic. One approach would be to use an anonymous sub e.g
    iterate(sub { $rep->attach(@_) }, @param);
    But as is suggested in the nodes above, it'll probably be better to refactor your sub.
    HTH

    _________
    broquaint

    update: doh! as chip points out, it helps if you pass the parameters

      Unfortunately you can't create a reference an object method
      Luckily this turns out not to be the case. can returns a reference to the method you're looking for, and undef if that method doesn't exist, so you can write code like:
      my $ref = $obj->can($meth_name); $ref->($obj, @params);
      if that floats your boat. Just remember that what's returned is a regular sub ref, so you need to pass in the object or class name as the first parameter.
        Luckily this turns out not to be the case. can returns a reference to the method you're looking for
        True ... kinda. It returns a reference to a class method to the appropriate sub, I know this is just playing with semantics, but when I call an object method I expect the caller to passed in to the method (well, in the world of perl at least). If you really wanted can to return an object method reference (or at least my expectation of one :) in that situation then you could use some code I whipped up for diotalevi's Why isn't ->can() curried?.

        Update: Elian rightly points out there isn't any difference between class and object methods, which I knew, but didn't write correctly in the node ('class method' ne 'sub in appropriate package'). Basically my point was that can returns a sub reference not a 'method' reference i.e you call it, and it implicitly makes the caller as the first arg in the arg list.
        HTH

        _________
        broquaint