Promises, promises

Ovid on 2009-07-08T19:23:59

This seems like such a useful little function. Can you guess what it does and why?

sub promise($) {
    my $subname = shift;
    my $package = caller;
    unless ($package->can('AUTOLOAD') ) {
        # this should be in import()
        require Carp;
        Carp::confess("Package ($package) does not implement AUTOLOAD");
    }
    my $fq_name  = "$package\::$subname";
    my $autoload = "$package\::AUTOLOAD";
    no strict 'refs';
    *$fq_name = sub {
        $$autoload = $fq_name;
        goto &$autoload;
    };  
}

In fact, unless there's something else which does this and there's a fatal flaw, I think I might just upload this to the CPAN.


Think so

Aristotle on 2009-07-08T20:43:56

Installs a stub that delegates to AUTOLOAD. Maybe because there are several of them in the class hierarchy and you want the one in the superclass to take precedence over the one in the subclass, for the methods it implements. Maybe it has to do with making UNIVERSAL::can work correctly.

Re:Think so

Ovid on 2009-07-08T22:01:37

You got it. The promise delegates to AUTOLOAD and AUTOLOAD, of course, can safely overwrite that promise, if needed. This allows can() to behave correctly with various modules which rely on AUTOLOAD to function more-or-less correctly, even if can hasn't been overridden. It also allows you to fulfill a requires for a Moose role.

One thing it doesn't do is try to replace a reference to itself. That might be annoying if someone does this:

if ( my $code = $object->can('some_promised_sub') ) {
    $code->(@args) for 1..10;
}

That's annoying because the AUTOLOAD call might be expensive.

Still not sure how good of an idea this is, but it seems useful.

OK, maybe I'm just being stupid...

mauzo on 2009-07-09T16:26:58

but how is this different from

sub foo;

(or

*$fq_name = \&$fq_name;

if you want to install them dynamically)?

Re:OK, maybe I'm just being stupid...

Ovid on 2009-07-10T08:13:41

You know, I think I'm the one who's being stupid :) As Aristotle points out, my version gives greater dispatch control, but I honestly hadn't thought of that (this reminds me of the time I started writing "tail -f" in Perl before I came to my senses).