Re: defined &{ $pkg . '::foo' } vs. $pkg->can( 'foo' )
by friedo (Prior) on Jul 14, 2005 at 20:36 UTC
|
Yes, the first tells you if a certain sub is defined in a certain package. The second tells if you a class can call a particular method. The main difference is that the second one knows about inherritence. | [reply] |
Re: defined &{ $pkg . '::foo' } vs. $pkg->can( 'foo' )
by ikegami (Patriarch) on Jul 14, 2005 at 20:35 UTC
|
can could potentionally match subs in parent classes, such as test in the following example:
package pkgA;
sub test {}
package pkgB;
our @ISA = qw( pkgA );
our @test;
{
no strict 'refs';
@methods = grep $pkg->can( $_ ), keys %{ $pkg . '::' };
}
| [reply] [d/l] [select] |
Re: defined &{ $pkg . '::foo' } vs. $pkg->can( 'foo' )
by dragonchild (Archbishop) on Jul 14, 2005 at 20:50 UTC
|
There's an additional issue - use of can() depends on a given method which can be overridden to do whatever the package author feels like. Now, this can be useful in the case of AUTOLOAD. However, you may not want AUTOLOADed methods to be brought over in that snippet (nor can some of them be brought over).
The defined way that merlyn did is the safest for general use (I would think), but there are specialized uses that may prefer can().
My criteria for good software:
- Does it work?
- Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
| [reply] |
Re: defined &{ $pkg . '::foo' } vs. $pkg->can( 'foo' )
by tlm (Prior) on Jul 14, 2005 at 22:27 UTC
|
Thanks for all the replies. The problem that served as context for the question is to devise an automatic way to define delegated methods.
A typical "delegated method" looks something like:
sub frobozz {
my $self = shift;
return $self->{ _delegate }->frobozz( @_ );
}
...where $self->{ _delegate } holds a reference to some other object. The first object basically passes the buck to the delegate.
My basic idea was to run through all the "public methods" that the delegate can perform (by plucking them out of its and its ancestors' symbol tables) and define a delegated method (like the one illustrated above) for each of those methods among these that the containing class cannot perform.
The fly in the ointment, of course, is that fishing functions out of symbol tables, in general, cannot distinguish between public methods (which are part of the delegate's API) and private methods or functions that have been imported by the delegate class, and neither of which belong to its API.
The only thing I can think of is that, if all the ancestor classes are ones that I control, then I can define those classes so that their private methods are easy to distinguish (e.g. with leading underscores) and so that they don't import anything. They either use fully qualified function names, or do something like:
BEGIN {
*_croak = \&Carp::croak;
}
I.e. import a function "by hand" but rename it in such a way that it can be easily filtered out.
(Or I can go nuts and assign all these non-API methods to lexical scalars.)
And yes, the whole scheme described above would miss any AUTOLOADed or runtime-defined methods of the delegate object. Again, I don't know a way around this, other than avoiding using such methods in those classes I control.
I suspect that, as is my habit, I am complexifying things... As always, your comments are most welcome.
| [reply] [d/l] [select] |
|
|
OK, here I'm replying to my reply to a post of mine. Pretty solipsistic... Never mind me.
One could argue that automating the generation of delegated methods should give off some pungent code-smell... Why? Because the only rationale for it is for the delegating class to be able to "track" the delegate class's API automatically, but if that's the case, maybe the delegating class should be inheriting instead. In other words, one could argue that the portion of a class A's API that is delegated to another class B should be decided by the designer of class A, irrespective of the changes in class B's API. (Of course, class B's API could shrink, which could in turn break some delegated methods, but IMO it is far more likely that, if it changes at all, the API of class B will grow, not shrink.) Therefore, instead of having class A automatically figure out which methods to delegate to the delegate class, these methods should be hard-coded in the definition of class A. This obviates the problem of distinguishing those functions in the delegate class's and its parents' symbol tables that belong to the delegate class's API from those that don't...
| [reply] [d/l] |
Re: defined &{ $pkg . '::foo' } vs. $pkg->can( 'foo' )
by japhy (Canon) on Jul 14, 2005 at 21:07 UTC
|
The first one does not mesh with your node's title. It says "of the symbols in $pkg, which are defined as functions in this current package?". If you write it as you did in your node title, grep defined ${$pkg . "::$_"}, keys ..., then it would be saying "of the symbols in $pkg, which are defined as functions in $pkg?".
| [reply] [d/l] |
Re: defined &{ $pkg . '::foo' } vs. $pkg->can( 'foo' )
by jdporter (Paladin) on Jul 14, 2005 at 20:54 UTC
|
O.k., you've gotten the answer to the underlying question, but you might still wonder what is the difference between those snippets of code, in terms of their practical effect. The first one answers the question, "Of the symbols defined in the given package, which ones are functions? (vs. scalars, arrays, etc.)" The second one answers the question, "Of the methods that the given class can handle, which ones are defined in the class, vs. in some ancestor class." It's worth noting that these tests can be fooled by AUTOLOAD and other aspects of the run-time dynamicity of perl.
| [reply] |
|
|
I have to pick a nit. The second one doesn't answer "of the methods that the given class can handle, which ones are defined in the given class?". The (psuedo)code for that would be @local = grep defined &{$class . "::$_"}, $obj->list_all_my_methods. The second one answers the question "of all the symbols in the given class, which ones are names of methods of the given class?".
Case in point:
package Parent;
sub foo { 1 }
package Child;
@ISA = 'Parent';
sub new { bless {}, shift }
$foo = 10;
package main;
my $pkg = "Child";
print join(", ", grep defined &{ $pkg . "::$_" }, keys %{ $pkg . '::'
+}), "\n";
print join(", ", grep $pkg->can( $_ ), keys %{ $pkg . '::' }), "\n";
This prints "new" on the first line, and "new, foo" on the second. I changed the defined() test a bit, because with $pkg in there, it's saying "of the symbols in $pkg, which are defined as functions in this current package I'm in?" rather than "... which are defined as functions in $pkg?".
| [reply] [d/l] [select] |
|
|
| [reply] |
Re: defined &{ $pkg . '::foo' } vs. $pkg->can( 'foo' )
by ysth (Canon) on Jul 15, 2005 at 12:31 UTC
|
$ perl -w
sub foo;
sub AUTOLOAD { print "called $AUTOLOAD" }
print "is foo defined? ",0+defined &foo, " does foo exist? ", 0+exists
+ &foo, "\n";
foo();
__END__
is foo defined? 0 does foo exist? 1
called main::foo
You almost always want to use exists &subname rather than defined &subname; there's no advantage in excluding declared-but-not-defined subs. | [reply] [d/l] |
|
|
| [reply] |
|
|
I don't see why. Pre-declaring subs is the responsible way to use AUTOLOAD. Why would you want to disallow it in your delegatees? Anyway, this qualifies as a difference between ->can and defined&.
| [reply] |
|
|