Re: Calling Madness
by broquaint (Abbot) on Sep 15, 2002 at 00:43 UTC
|
{
package PKG;
sub safe_sub {
my $self = shift if @_ == 3
and UNIVERSAL::isa($_[0], __PACKAGE__)
or $_[0] eq __PACKAGE__;
my($hash, $string) = @_;
print $hash->{foo}, ':', $string, $/;
}
sub new { bless {}, shift }
}
my $obj = PKG->new();
print '$obj->safe_sub - ';
$obj->safe_sub({'foo' => 'bar'}, 'cool');
print 'PKG->safe_sub - ';
PKG->safe_sub({'foo' => 'bar'}, 'cool');
print 'PKG::safe_sub - ';
PKG::safe_sub({'foo' => 'bar'}, 'cool');
package PKG;
print 'safe_sub - ';
safe_sub({'foo' => 'bar'}, 'cool');
__output__
$obj->safe_sub - bar:cool
PKG->safe_sub - bar:cool
PKG::safe_sub - bar:cool
safe_sub - bar:cool
Which seems to work. If you're looking for methods which act like functions and vice versa check out the source for CGI.pm as it performs a similar kind of magic.
HTH
_________ broquaint | [reply] [d/l] |
Re: Calling Madness
by chromatic (Archbishop) on Sep 15, 2002 at 02:36 UTC
|
It is madness. Don't do it. Instead, write clear documentation that tells how you expect people to use your module, and let them take the hint.
If you don't take my advice, at least realize that you've effectively broken subclassing with your regular expression. (You're also going to have a dickens of a time overriding safe_sub().)
| [reply] |
Re: Calling Madness
by jkahn (Friar) on Sep 15, 2002 at 00:35 UTC
|
I am not entirely sure what you're asking, but I'll try to paraphrase:
Is there a way I can construct a package subroutine so that, regardless of whether:
- I call it as an instance method
- I call it as a
packageclass method
- I call it by its fully-qualified Pack::method name
it will do the Same Thing each time?
My answer: I think so. I'm not sure why you would want to do this, but it's the only thing I can see here.
Here's a method that would act that way (although it's not quite what you suggested). (untested):
package thisPack;
sub smartish_sub {
my $self; # for instance reference, if called that way
my $class; # for classname, if called that way
if (ref $_[0]) {
if (UNIVERSAL::isa($self,'thisPack')) {
# ( corrected from earlier ->isa call)
# it's an instance method invocation
my $self = shift @_;
}
# else it's not an instance, but it is a ref, so
# it must be a fully-qualified invocation
}
else {
# not a reference; ought to be class invocation
my $class = shift;
die "first argument to smartsub must be hashref\n"
unless UNIVERSAL::isa($class, 'thisPack');
}
# now any class- or instance- invocations have been
# shifted off @_
my ($hash, $string) = @_; # might want error-checking here.
print "$hash->{foo}\n$string";
}
sub new {
bless {}, shift;
}
YMMV.
Updated (almost immediately): used UNIVERSAL::isa() everywhere, not ->isa().
second update: clarified package vs. class language. | [reply] [d/l] [select] |
|
|
You're on the right track :)
See - this sub can be called by any method so I need to make sure everytime it's called I either shift off the package/class info or do nothing.
My orgional code to do this (shift if ref $_[0] or $_[0] =~ /^PKG/;) doesn't work when your calling the sub by its fully-qualified "Package::method" name and $_[0] happens to be a hash ref.
So maybe this will help in understanding my problem: shift if (ref $_[0] and $_[0]-is-the-ojbect-itself,-not-a-normal-hash-ref) or $_[0] =~ /^PKG/;
| [reply] [d/l] [select] |
Re: Calling Madness
by dws (Chancellor) on Sep 15, 2002 at 00:47 UTC
|
I'm trying to create a 'safe sub' that when called using any of the methods a sub can be called with will still work the same.
Time spent studying CGI.pm will pay off in many ways, including for this particular problem.
| [reply] |
|
|
| [reply] |
|
|
I did look at CGI.pm but don't totally understand the UNIVERSAL::isa stuff. And I *think* it's done a little differently then what I need in CGI.pm. (It creates a new ojbect if it's not there whilst I just want to get rid of the object if it is there.)
| [reply] [d/l] |
Re: Calling Madness
by sauoq (Abbot) on Sep 15, 2002 at 08:35 UTC
|
Right off the bat: I agree with chromatic. Don't do it.
Now that I've said that, if you aren't doing anything with the object or package (in the cases where it is invoked as an object or class method) and the rest of your argument list isn't variable, then just pull your arguments from the back end of the array.
my ($string, $hash) = (pop, pop); # Reverse order... UGLY.
my ($hash, $string) = @_[-2,-1]; # Keep "normal" order. (Better)
my ($w, $x, $y, $z) = @_[-4..-1]; # Range operator makes long lists ea
+sy.
This avoids all the unneeded argument checking on throwaway arguments.
-sauoq
"My two cents aren't worth a dime.";
| [reply] [d/l] |
Re: Calling Madness
by rir (Vicar) on Sep 15, 2002 at 03:18 UTC
|
No, not quite.
You have to accept:
PKG::safe_sub( "PKG", $other_args);
as the same as:
PKG::safe_sub( $other_args);
safe_sub PKG $other_args;
Also I think you want shift if ref $_[0] eq "PKG" or $_[0] eq "PKG";
as your test. | [reply] [d/l] [select] |
|
|
| [reply] [d/l] |
|
|
As Aristotle says, ref $_[0] eq "PKG" will break inheritance.
I think that illustrates a serious problem with the concept. I took
the stance that:
Class::derived( $not_blessed);
should do the same as:
$class->derived( $not_blessed);
and decided that inheritance was not allowed because the
first form was desired.
If allowing naive users to use the various calling conventions
was the idea, and why else, I thought this was the clear choice.
The following, and more, need to be considered:
Class::derived( $class_obj); # Jack
Class::derived( Class $not_blessed); # Queen
Class->derived( $not_blessed); # King
$class_obj->derived( $not_blessed); # Ace
Class::derived( "Class", $not_blessed); # Joker
The last is the joker. How will you distinguish between
the Joker and the Queen?
And what about Jack? Is that the same as:
$class_obj->derived;
or the same as: $class_obj->derived( $class_obj);
| [reply] [d/l] [select] |
|
|
|
|
Re: Calling Madness
by Anonymous Monk on Sep 19, 2002 at 00:22 UTC
|
Wouldn't this work: shift if UNIVERSAL::isa($_[0], __PACKAGE__) or $_[0] eq __PACKAGE__; | [reply] [d/l] |