in reply to Callback Design

1. This dirty bit of nastiness appears to do what you want:
package Foo; my $coderef = sub { no strict 'refs'; ${ (caller)[0] . "::global" } }; $global = 'in Foo'; package Bar; $global = 'in Bar'; print &$coderef, "\n";
..but why on earth do you want to do this? :)

This kind of magic side-effect can cause incredibly hard-to-diagnose bugs: someone might move the subroutine call into another package, never suspecting that it might vary it's behaviour based on something as oblique as compiler directives in effect in the most-recent calling code.

2. Using $_ for callbacks is fine AFAIK, as long as you are careful and the callbacks are short. I've used things like hostname_cleanup => sub { s/test\.userfriendly\.org$//i } to pass regexps in from configuration files before I learned about qr//. I too will be interested to see what the real experts think!

Replies are listed 'Best First'.
Re: Re: Callback Design
by MeowChow (Vicar) on Jan 16, 2001 at 04:47 UTC
    Impressively diry and nasty :) What I'm looking for is a way to keep the anonymous sub the same, and override it's package when it is called. The idea is to have callback params readily available as package variables.

    I believe the Safe module could do this, but it seems like terrible overkill.

      Hmm. Let me see if I understand: you want to be able to do something like grep or map, where your code gets passed a subref which you then call back?

      If so, you don't need to worry about changing packages at the time you call it, since it will have already picked up the proper package when it was defined (and compiled) in the caller's code:

      package my; $global = 'in_my'; sub own_map(&@) { my $code = shift; my @return = (); push @return, $code->() for @_; @return; } package main; $global = 'in_main'; print my::own_map { $_, " ", $global, "\n" } (1..20); # prints "1 in_main\n", "2 in_main\n" and so on
      In the above code, my::own_map could have molested ${ (caller)[0] . "::global" } to pass a value in to the block. I guess this might be OK (although it's clearly an abuse of caller, which AFAIK was intended for debugging), as long as it's well documented and you are careful to localize everything.

      Updated: removed a confusing and unneeded $_ argument on the line that calls the callback. Oops!

        Ah, you just showed me something cool, that I can do without the 'sub' declaration if I prototype the callback-setter.

        But I guess I'm not being very clear as to my primary objective. I would like to have something like the following:

        package MyModule; my $callback; sub set_callback { $callback = shift; } sub exec_callback { # the next three lines don't work, but they are indicative of what I + would like # to see happen... i want $name, $street, $city, $zip to be made ava +ilable as package # globals to the anonymous callback sub... in other words, I don't w +ant the callback # to execute in it's own package, I want it to execute in MyModule:: +ThrowAway package MyModule::ThrowAway; our ($name, $street, $city, $zip) = @_; &$callback(); package MyModule } package main; # set callback to check that name and zip are both correctly formatted # notice that callback sub assumes that $name and $zip have been set f +or it, not # passed in @_ # MyModule::set_callback(sub { $name =~ /^[a-zA-Z\s]+$/ and $zip /^\d+$/ + }) MyModule::exec_callback('Bob', '600 1st St.', 'Beverly Hills', 90210);
        Now that I think about it, this could never work under use strict, since $name and $zip are undeclared at the time the callback sub is formed.

        update: cleared up a few confusing things in my code