1

Is it possible to get a subroutine reference from a Moose object in Perl? For example:

package A;
use Moose;
1;

sub mm {
  print "Hello\n";
}

Then I make an A object:

use warnings;
use strict;
use A;

my $o=A->new();
my $sub=\&{$o->mm};
$sub->();

This does not work. It gives error:

Undefined subroutine &main::1 

If I know that $o is an A object, I can of course solve this using my $sub=\&A::mm; instead. But in the case, where I am only given $o is it possible to extract the reference to a function mm ?

Håkon Hægland
  • 39,012
  • 21
  • 81
  • 174
  • possible duplicate of [How does one get a method reference when using Moose](http://stackoverflow.com/questions/4870070/how-does-one-get-a-method-reference-when-using-moose) – ThisSuitIsBlackNot Aug 25 '14 at 19:06
  • If you need create an "alias", you can hack it with the `$mmref = *A::mm; $mmref->()` - but this isn't an recommented common practice, and probably has many drawbacks... – clt60 Aug 25 '14 at 19:14
  • Although it soesn't make a difference in this case, Your `1;` should be at the bottom of the file. – Borodin Aug 25 '14 at 21:04
  • @Borodin Thanks..In which case would it make a difference not to have it at the bottom? – Håkon Hægland Aug 26 '14 at 07:24
  • 1
    @HåkonHægland: Do you have a particular desire to put it somewhere else? The reason it's conventionally at the bottom of the module is that it's eay to find there. It's simple to skip to the end of the file and check whether there's a `1;` there, and add one if not. There's no reason that I can think of to put it elsewhere. – Borodin Aug 26 '14 at 12:54

2 Answers2

2

The code you're using calls $o->mm and treats the result as a sub reference (symbolic or otherwise), dereferences it, and creates a new reference to it.

If you want a sub that calls $o->mm, you'll need to make one.

my $sub = sub { $o->mm };

Or if the args received by the sub are supposed to be passed to $o->mm,

my $sub = sub { $o->mm(@_) };
ikegami
  • 367,544
  • 15
  • 269
  • 518
1

Taking references of methods goes against the grain of object-oriented design, but you can do it just fine if you use UNIVERSAL::can. UNIVERSAL is the ultimate base class from which everything inherits, and it is defined implicitly for every Perl program.

Leave your module as it is (although the use Moose is having no effect at present) and change your program to this

use strict;
use warnings;

use A;

my $o = A->new;
my $sub = $o->can('mm');
$sub->();

output

Hello

But do remember that a method will normally have been written to expect either the class/package name (for a class method) or an object reference (for an object method) as its first parameter.

Since this way circumvents Perl's method call syntax, you would have to do it yourself, so the call should look like

$sub->($o)

although in this case mm isn't a real method so it doesn't care what you pass to it.

Borodin
  • 126,100
  • 9
  • 70
  • 144