Method theft

hex on 2006-10-26T14:05:49

So, I just wrote the following: steal a method wholesale from somewhere else. (Not incredibly sophisticated, but new for me.) I don't currently have a particular use for it, but it seems to have potential for fun.

#!/usr/bin/perl

use warnings; use strict;

package Foo;

sub foo { print "1\n"; }

package Bar;

sub new { bless {}, shift; }

sub steal { my ($self, $call) = @_; my @segments = split('::', $call); my $method = pop @segments; my $class = join '::', @segments; no strict 'refs'; *{__PACKAGE__ . "::$method"} = *{$class . "::$method"}; $self; }

package main;

Bar->new->steal("Foo::foo")->foo;


Or with Sub::Install

ferreira on 2006-10-26T14:27:42

I think you may do the same with Sub::Install (by rjbs). The code would be something like:

  use Sub::Install;
  Sub::Install::install_sub({
    code => 'foo',
    from => 'Foo',
    into => 'Bar',
  });

Note: Your code currently does not handle packages like 'Data::Foo::Glub' as the source.

Re:Or with Sub::Install

hex on 2006-10-26T14:56:02

I think you may do the same with Sub::Install (by rjbs).

Smooth! Thanks for the tip.

Note: Your code currently does not handle packages like 'Data::Foo::Glub' as the source.

Good call. I've fixed it now so that it does.

Nothing special

Aristotle on 2006-10-26T17:26:06

That’s just how exporting works in Perl.

You’re better off doing it like so, btw:

*{__PACKAGE__ . "::$method"} = \&{$class . "::$method"};

That affects only the subroutine slot of the destination glob, and avoids nuking it in entirety.

You’re doing a lot of pointless busywork, though:

sub steal {
    my $self = shift;
    my ( $symref ) = @_;

    ( my $methname = $symref ) =~ s/^.*:://;

    { no strict 'refs'; *$methname = \&$symref; }

    return $self;
}

Re:Nothing special

hex on 2006-10-27T09:38:56

That’s just how exporting works in Perl.

Cool. All part of the learning process.

You’re better off doing it like so, btw... That affects only the subroutine slot of the destination glob, and avoids nuking it in entirety.

Yeah. I realised that a little later after some more reading on globs.

You’re doing a lot of pointless busywork, though:

I call it a first pass! The split/pop/join would most likely have become a regex the next time I looked at it. I see that it also obviates the need to use __PACKAGE__. Handy.

On the other hand, the idiom of ( my $foo = $bar ) =~ s/x/y/; is a new and valuable one to me, which will definitely save me some time in future - thank you.

Re:Nothing special

Aristotle on 2006-10-27T12:46:37

Oh yeah. That’s a specific instance of a broader idiom that comes in many forms. An instance you have probably encountered elsewhere is chomp( my @line = <$fh> );. It looks somewhat different, but it operates on the same principle: using parens to increase the precedence of an assignment so it happens before another part of the expression, which then operates on the lvalue of the assignment.

Use it sparingly, though, as overuse of this idiom can easily degrade readability.

that's not theft

jhi on 2006-10-27T03:25:09

If you *steal* you should delete the method from the original owner, no?

Re:that's not theft

hex on 2006-10-27T08:53:05

I guess it's theft in the same way that "downloading mp3s is theft!!1!" :)

Re:that's not theft

hex on 2006-10-27T09:16:01

Although, that said, no doubt actual theft is possible (and that there's already an Acme:: module to do it...).

The theiving magpie

ivorw on 2006-10-27T15:54:39

This reminds me of Acme::Magpie