This and other RFCs are available on the web at
http://dev.perl.org/rfc/
=head1 TITLE
Class Methods Introspection: what methods does this object support?
=head1 VERSION
Maintainer: Mark Summerfield <[EMAIL PROTECTED]>
Date: 28 Sep 2000
Mailing List: [EMAIL PROTECTED]
Number: 335
Version: 1
Status: Developing
=head1 ABSTRACT
This RFC proposes a new UNIVERSAL method which would be used thus:
my @method_names = $object->methods(); # OR MyClass->methods();
=head1 DESCRIPTION
How can we tell which methods an object supports? If we know the names
of the methods we're interested in we can use C<$object->can('methodname')>.
However if we don't know the possible names then we're stuck. This RFC
proposes a new UNIVERSAL method which would be used thus:
@method_names = $object->methods(); # OR MyClass->methods();
The C<methods()> method would I<not> be able to determine definitively
all the methods that are available: firstly it is perfectly possible to
define new methods at runtime using C<eval>; secondly if the class has an
C<AUTOLOAD> method then the methods it supports may not be determinable.
In the case of classes that use C<AUTOLOAD> the string 'AUTOLOAD' would
naturally be one of the method names returned so at least the programmer
would be aware that any number of other methods may exist. Thus C<methods>
would return the list of methods known to be available to the object at
the time that C<methods> is called.
C<methods> could of course be over-ridden on a class-by-class basis; for
example, if your class supported fifty methods, but half of them were so
rarely needed that they were created on-the-fly in AUTOLOAD you could
return all their names if you override C<methods> and return the list of
names yourself. Furthermore as a method of UNIVERSAL C<methods> would not
collide with any existing or subsequent function of that name.
In terms of RFC 188 I would expect C<methods> to return public methods
only.
Why not simply use C<isa> to determine the class? Often knowing the
class is all that is necessary; however sometimes it is useful to know
what the possible methods are. Imagine we have a simulation system with
a core application that sends and receives signals to the objects it is
simulating (by calling their methods). Users may implement the objects
they want simulated by creating their own classes for each type of object.
One approach to this is to supply the user with a base class from which
they inherit. This has a disadvantage -- a given method is always called
in response to a given event because each event in the simulator maps to a
method in the base class. Sometimes we want to "wire up" the simulated
object so that on a particular run event A calls method A, but on another
run event A calls method B. Hardwiring this isn't a problem, but what if
we want to provide the user with this choice interactively -- well, if we
don't know what methods the class supports in the first place we cannot
give the user a list to choose from. The solution is to be able to
introspect on the class they've chosen and show them the list of methods
available; they can then choose which to wire up to which events in the
simulator. I am sure that there are other examples where object
introspection would be useful.
=head1 IMPLEMENTATION
I think this needs to be implemented in Perl itself so that it can avoid
private methods and can be implemented efficiently, but here's some code
mangled from perl5db.pl:
# test.pl
#
# Unlike a built-in this method cannot distinguish between `real'
# methods and `constants' defined with use constant (but hopefully
# that pragma will go away).
# We skip private methods by ignoring names that begin with an
# underscore; we skip overloaded methods by ignoring names that
# begin with an open parenthesis.
package UNIVERSAL;
use strict;
sub methods {
my $thing = shift;
my $class = ref($thing) || $thing;
my @list;
no strict 'refs';
# Based on methods_via() in perldb5.pl
for my $name (grep {not /^[(_]/ and
defined &{${"${class}::"}{$_}}}
keys %{"${class}::"}) {
push @list, $name;
}
@list;
}
1;
With the above saved as `test.pl', you could do the following in the
directory in which you put it:
% perl -de0 -MCPAN
main::(-e:1): 0
DB<1> require 'test.pl'
DB<2> p join ", ", sort CPAN->methods()
AUTOLOAD, DESTROY, all, all_objects, checklock, cleanup, cwd,
delete, exists, fill, find, finddepth, getcwd, has_inst,
instance, new, shell, wrap
=head1 REFERENCES
RFC 188: Objects : Private keys and methods
RFC 193: Objects : Core support for method delegation
RFC 265: Interface polymorphism considered lovely
perl5db.pl