in reply to Caveats when using anonymous subs as subroutine arguments

Granted it may be a relic of your sample simplification, but in this case I might had factored out the common bits into a helper that looks up the exact arguments from a hash instead (and then sets up methods for each task based on the contents of the hash).

my %helper_args = ( Task1 => [ qw(ARG1 ARG2 ARG3) ], Task2 => [ qw(ARG6 ARG2 ARG1 ARG5) ], ## ... ); for my $task ( keys %helper_args ) { *{"Do$task"} = sub { $_[0]->_common_runner( $task, @_[1..$#_] ) }; } sub _common_runner { my $self = shift; my $task = shift; ## "Task1", "Task2", ... my @rest = @_; if( !$self->TaskIsDone() and (my( $setup ) = $self->can( "Setup$task +" )) ) { $self->$setup(); } my @args = @{ $helper_args{ $task } || [] }; $self->CommonTask( @args, @rest ); }

Alternately create a common base class and then have that base class' CommonTask calls methods on itself (with the base class' implementations being noops / stubs); in other words the Gang Of Four "Template Method Pattern".

Update: Oh, and to actually answer your question no that's not a totally bletcherous solution and that is one of the "accepted" usages of prototypes (to get new keyword-like syntax).

The cake is a lie.
The cake is a lie.
The cake is a lie.

Replies are listed 'Best First'.
Re^2: Caveats when using anonymous subs as subroutine arguments
by Glav (Novice) on Dec 02, 2008 at 01:56 UTC
    I like the idea of the common default arguments hash; that would make it easier to update if/when the defaults need to change. And as you suspected, the actual methods involved were not quite as simple. A major factor in deciding to go this route came from the 'if' block contents. Most of subroutines used the same chunk of code with small differences (if any); I put that work into it's own subroutine and passed it directly. Others do mostly the same work, with minor additions and changes. (A side note: there's actually now a common interface to using these methods (eg, DoTask( TASK_1, @args); ) which makes these individual names simply a relic of maintaining the interface.)

    Since the setup is reused by maybe 80% of these methods and others use minor tweaks or additions, I'd want to specify that the same setup is used. That's easy to do with an individual setup method for each 'task', but that would create several new subroutines that simply call the common setup subroutine, leading me back to the same initial problem! I could pre-specify which specific setup to use in a constant, and then build the setup methods based on that string using 'can'; from there I'd simply look up a code reference. And in your example, that would happen at the time the module was 'use'd, making the lookup only happen once, right? Does perl resolve that reference right then, or does it still look it up every time the method is called? If it resolves it then, that seems pretty swanky.

    I'd have to make several extra minor subroutines that only ever get called from one place for each of the 20% corner cases, though. That's what led me to think of creating a common setup subroutine for most and anonymous subs for the one off's, and pass them in via a code reference. If I understand it right, the way I did it, perl will have to reconstruct that anonymous sub every time that method is called. The ones that simply use a reference to the common setup wouldn't, though.