harsha.reddy has asked for the wisdom of the Perl Monks concerning the following question:

In the following code, in the sub-routine names new(), I have used something like:

_proc => $action1,

my perception is that, in this case _proc holds a copy of the value present in $action and this is a costly method doing things, as the $self object would be very heavy to pass-on or call.
I tried to declare something like:
_proc => \$action1,

But it did not work out well for me.. :(
Please advice.

package Engine; use strict; use My::Module; my $action1 = sub { $pkt = shift; #where $pkt is an object of type My:Module:Object my $id = $pkt->get('ID'); #........ #do this #do that... print $id; } sub new { my $class = @_; return bless { _xp => My::Module->new(), _proc => $action1, } }; sub routine { my $s = shift; $s->{_xp}->process(); my @arr = $s->{_xp}->getvalues("packet"); map($action1->($_), @arr); }

Replies are listed 'Best First'.
Re: A way registering an anonymous sub in $self?
by ikegami (Patriarch) on Mar 05, 2010 at 19:00 UTC

    _proc holds a copy of the value present in $action and this is a costly method doing things,

    Except all $action contains is a reference. Creating a new reference, copying it, then destroying it, all to avoid copying a reference... not very productive.

    If you were talking about a string, there might be some gains. You could, for example, store a reference to the string in the object. The catch is that you'll have to dereference it later when you want to use what you stored. That's probably what was missing in your broken code.

Re: A way registering an anonymous sub in $self?
by BrowserUk (Patriarch) on Mar 05, 2010 at 19:50 UTC
    and this is a costly method doing things, as the $self object would be very heavy to pass-on or call.

    I'm not sure that I understand you, but I think you may be misunderstanding what your code does.

    When you assign _proc = $action1, you are simply storing a reference to the code. This is no more costly in terms of either cpu or memory than storing an integer.

    The only time any additional cost is incurred, is when you invoke that code via the reference at:

    map($action1->($_), @arr);

    And that seems to be exactly what you want (and need) to do.

    The only possibility of reducing that cost, is if you find that $action1->( ... ) is being called with the same input parameter many times. In that case, you may be able to defer the cost of the call, by caching the results and only calling $action1 if the required result is not already in the cache:

    my %cache; sub routine { my $s = shift; $s->{_xp}->process(); my @arr = $s->{_xp}->getvalues("packet"); map{ $cache{ $_ } ||= $action1->($_) } @arr); }

    Note: //= would be better than ||= if you are using v5.10 or later.

    There is a module, Memoize that will do this for you, but it only appears to work on named subs, not code references.

    Update: Corion points out that I hadn't read far enough into the Memoize docs, and that it will accept a code reference and return a new code reference you should use in its place.

    That said, the above will work more quickly, though it could almost certainly be implemented better.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.