I'm working on a package, hopefully done by this weekend, where the user's data is stored internal, and there are several 'hooks' for which the user can modify this data. E.g., the code from the user end looks something like:
my $package = My::Package->new( \&user_sub ); $package->add_data( @user_data ); my $value = $package->operate_on_all_data(); sub user_sub { # code here }

The user's code will need to have predefined variables that will work on each object in turn. If the only thing they were allowed access to was the data itself, then I would use $_ as below:

# in My::Package sub operater_on_all_data { my $value; foreach ( @internal_data_storage ) { $value += &user_sub_variable(); } } # in user_sub sub user_sub { return $_ * 2; }
But I have a case where I want to supply not only the user the data to work with, but some current state information that is not accessible from the class interface (for good reason) that would change with each data that is processed. The question becomes, how to you approach this problem ?

There are two readily obvious solutions: First, one could use package-level globals (aka Helpers) that could be referenced, e.g.:

# in My::Package sub operater_on_all_data { my $value; my $i = 0; foreach ( @internal_data_storage ) { $helper = $i++; $value += &user_sub_variable(); } } # in user_sub sub user_sub { return $_ * 2 * $My::Package::helper; }
This is the method that File::Find uses; $_ is the file name, while $File::Find::dir is the current directory, plus some other helpers. This is nice and extendable if more helper variables are needed, but it can make the user's code look messy.

The other alternative is to pass arguements to the user's sub:

# in My::Package sub operater_on_all_data { my $value; my $i = 0; foreach ( @internal_data_storage ) { $helper = $i++; $value += &user_sub_variable( $i++ ); } } # in user_sub sub user_sub { my $multiplier = shift; return $_ * 2 * $multiplier; }
And while this cleans up the code for the user drastically, it forces an 'order' on the helper variables. In addition, if new helper variables are added, the order of the sub might change and break existing user code. There are some ways of fixing this, such as simply giving the user a hash with predefined keys, but then this starts making the code ugly again.

As a side problem, I'm also considering the case when I need to pass two data items to the user sub. sort nicely gives you $a and $b to work with, but that's a perl internal. In addition, $_ would be a bad way to approach it, since which of the two would you set $_ to, and where do you set the other data? So if I went the way of package-level helper variables, this would still work but increase the ugliness of the user's code, while going with passing arguements would make it simple for the user but again suffers from the problems listed above.

Any suggestions on which way is considered better? Or is there another way that I'm missing?


Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain

In reply to Passing package-level/helper variables to user coderefs by Masem

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.