0

I am trying to find a general solution to getting a reference to a method in a module. Assume that we have a Hello.pm module with a single method in it called "hello".

In a calling program, one would write

use Hello;
Hello->hello('Hi There');

The module is defined as:

package Hello;
sub hello {
 my $object=shift;
 my $greeting=shift;
 say "$greeting";
 return;
}
1;

How do I get a code reference to my module test of hello? Eventually I want to build a dispatch table and be able to load it with any number of methods located in other modules.

This does not work:

my $code_ref=&{Hello->hello}

and invoke it like this:

$code_ref->('Hi There');

Any ideas? Thanks!

2 Answers2

2

You want to make a subroutine call ($code_ref->(...)), but you want to call a method. That means you'll have to create a subroutine that calls the method, and get a reference to that subroutine instead. As the following shows, this is quite easy to do:

my $code_ref = sub { Hello->hello(@_) };
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • Unfortunately,It does not work. When the sub is located within the same module or call program, it is straightforward: $code_ref=&hello and to execute I would run $code_ref->{$argument) – Sammy Esmail Aug 31 '15 at 18:26
  • 3
    I assure you it does. `my $code_ref = sub { Hello->hello(@_) }; $code_ref->('Hi There');` will do the same thing as `Hello->hello('Hi There');`. – ikegami Aug 31 '15 at 18:28
  • Okay. The issue that I have is that when obtaining a code_ref, the call must include the object name. So $code_ref=&Hello::hello and then the call is $code_ref->('Hello',$argument). Without a code_ref, the object name is implicitly passed. Unfortunately, I could not get your format to work. I must be doing something wrong. – Sammy Esmail Aug 31 '15 at 18:44
  • I don't know what you did wrong if you don't show it. – ikegami Aug 31 '15 at 18:49
  • @SammyEsmail: If you want to use ikegami's solution then it's wrong to call the code reference as `$code_ref->('Hello',$argument)`. It should be just `$code_ref->($argument)`. The subroutine that `$code_ref` refers to will add the package name as the first parameter – Borodin Aug 31 '15 at 22:42
  • Hello Ikegami. Your solution indeed works. Here is what I did: I took the code reference as you stated: $code_ref=sub {Hello->hello(@_) } and then called $code_ref->('This Works'). It does work. And thank-you so much! – Sammy Esmail Sep 01 '15 at 15:54
  • Yes. I missed the concept of the prototype @_ as part of the code creation. I am happy dude! – Sammy Esmail Sep 01 '15 at 16:51
  • 1
    That's not a prototype. `@_` is the array that contains the arguments. You know those `shift` in your code? They're short for `shift(@_)`. – ikegami Sep 01 '15 at 16:51
1

If you're using this for a dispatch table, let the table do the heavy lifting by passing in a key instead of creating a generic cref and telling it which class to call the sub from:

use warnings;
use strict;

package Hello;
sub hello {
    my $class = shift;
    my $msg = shift;
    print "$msg\n";
}

package Bye;
sub bye {
    my $class = shift;
    my $msg = shift;
    print "$msg\n";
}

package main;

my %dt = (
    Hello => sub { Hello->hello(@_); },
    Bye => sub { Bye->bye(@_); },
);

$dt{Hello}->("hi there");
$dt{Bye}->("see ya!");
stevieb
  • 9,065
  • 3
  • 26
  • 36
  • 1
    My answer assumes the OP needed a callback since they said they needed to call it as `$code_ref->('Hi There')`. If it's not a callback, then you can just use `$class_or_obj->$method_name(@args)` instead of a dispatch table. – ikegami Aug 31 '15 at 19:05
  • Yes. This was my intention. I learned dispatch tables from Higher Order Perl but in his examples all his subs were defined in the same file. Thanks! – Sammy Esmail Sep 01 '15 at 15:58