Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?

See if a certain package has a certain sub, without executing that sub

by muba (Priest)
on Mar 20, 2004 at 15:03 UTC ( #338296=perlquestion: print w/replies, xml ) Need Help??
muba has asked for the wisdom of the Perl Monks concerning the following question:


I am writing a simple plugin system. I'm not sure whether I'm going to use it, but it's more like a way to explore Perl.

So, I have an array which contains packages names. Those packages should have a sub 'ReceiveMessage'.
A package called Communications contains a sub 'SendMessage'.
This SendMessage loops over the array to check which packages do have a ReceiveMessage and send a message to it. Currently, the array consists of one item: "Communications".

package Communications; sub SendMessage { my $msg = join("", @_); foreach my $cpack (@main::plugpack) { if (defined eval "${cpack}::ReceiveMessage") { eval "\&${cpack}::ReceiveMessage('$msg')"; } } } sub ReceiveMessage { print "Communications::ReceiveMessage('$_[0]')\n"; }
Of course I call the SendMessage sub once: &Communications::SendMessage("Hello, World!");
The strange thing is, I get output like I called SendMessage twice:
Use of uninitialized value in concatenation (.) or string at D:\device +\modem\internet\Xitami\cgi-bin\ line 48. Communications::ReceiveMessage('') Communications::ReceiveMessage('Hello, World!')
It appears to me that ReceiveMessage is not only called when the message is sent, but also when SendMessage checks it's existance. How can I prevent this?

Update: just clarified the last paragraph a little
Update: removed line of code which was coded in a inconsistent style and only was there for debug purposes :)

Replies are listed 'Best First'.
Re: See if a certain package has a certain sub, without executing that sub
by gmax (Abbot) on Mar 20, 2004 at 15:27 UTC

    Use the can method (it's a method of the UNIVERSAL package, so every class in Perl has access to it).

    #!/usr/bin/perl use strict; use warnings; package Communications; sub SendMessage { my $packages = shift; my $msg = shift; for (@$packages) { if ($_->can('ReceiveMessage') ) { $_->ReceiveMessage($msg); } else { print "$_ can't ReceiveMessage\n" } } } sub ReceiveMessage { print __PACKAGE__, "::ReceiveMessage('$_[1]')\n"; } package Second; sub ReceiveMessage { print __PACKAGE__, "::ReceiveMessage('$_[1]')\n"; } package Other; sub nothing { print "\n"; } package main; my @packages = qw(Communications Other Second); Communications::SendMessage( \@packages, 'hello'); __END__ output: Communications::ReceiveMessage('hello') Other can't ReceiveMessage Second::ReceiveMessage('hello')
     _  _ _  _  
    (_|| | |(_|><
      Wow! This one is great! It's also nice to read:
      "if it can receive message" :)
      Thank you a lot!

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://338296]
Approved by gmax
Front-paged by cchampion
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (7)
As of 2017-07-28 16:30 GMT
Find Nodes?
    Voting Booth?
    I came, I saw, I ...

    Results (431 votes). Check out past polls.