How to forward arguments to a super function in perl? - perl

I'm a very perl beginner, but I have (more or less) this code:
package Base;
sub foo{
my ($self, $first, $second, $third) = #_;
# do some magic here!
}
package Subclass;
use base qw(Base);
sub foo{
my ($self, $first, $second, $third) = #_;
#do something with $first only
return $self->SUPER::foo($first, $second, $third);
}
And the method is called with: $self->foo("Hey", "what's", "up");
Is there a more concise way to call SUPER::foo(), without repeating the list of all args again?

you can re-use #_ to pass the arguments like this
$self->SUPER::foo(#_);
Since the first element of #_ is the "object" used to call the class method, you don't want to pass that into the parent class method twice, so you should use shift to remove it first.
sub foo{
my $self=shift;
my ($first, $second, $third) = #_;
#do something with $first only
return $self->SUPER::foo(#_);
}

This might actually be one of the valid uses of the &function; call.
E.g.
&SUPER::foo;
As documented in perlsub - this makes #_ visible to the called sub.
It should be used with care, because it's deviating from what you might normally expect to happen - it's not passing args, it's making the same set 'visible'.

Related

Passing argument to a Perl class subroutin

My code is pretty simple. I have a subroutin getModemHost under a package named smconfig.
sub getModemHost {
print 'Modem-'.$_[0].'.Host';
}
when Im calling this subroutin with an argument, I see strange values rather than what I passed. The below line prints Modem-smconfig=HASH(0x9433968).Host. I am expecting Modem-1.Host
$smconfig->getModemHost(1)
The first argument to a method is the invocant, i.e. the object. Use $_[1] for the real first argument. Or, more readable:
sub getModemHost {
my ($self, $modem_number) = #_;
print "Modem-$modem_number.Host";
}
See perlobj for details.
Or something very common:
sub myObjectMethod {
my $self = shift;
...
# do here what you like to do with $_[0]
# for we have removed the first parameter
...
};

Is it possible to get all valid methods for a particular Perl class?

Is it possible to get all valid methods for a particular Perl class?
I am trying to manipulate the symbol table of a class and get all of its methods. I found I can separate out the subroutines from the non-subroutines via the $obj->can($method), but that doesn't do exactly what I think it does.
The following returns:
subroutine, Property, croak, Group, confess, carp, File
However, subroutine isn't a method, (just a subroutine), and croak, confess, and carp were all imported into my package.
What I really want to print out is:
Property,Group, File
But I'll take:
subroutine, Property,Group, File
Below is my program:
#! /usr/bin/env perl
use strict;
use warnings;
use feature qw(say);
my $sections = Section_group->new;
say join ", ", $sections->Sections;
package Section_group;
use Carp;
sub new {
return bless {}, shift;
}
sub Add {
my $self = shift;
my $section = shift;
}
sub Sections {
my $self = shift;
my #sections;
for my $symbol ( keys %Section_group:: ) {
next if $symbol eq "new"; # This is a constructor
next if $symbol eq "Add"; # Not interested in this method
next if $symbol eq "Sections"; # This is it's own method
push #sections, $symbol if $self->can($symbol);
}
return wantarray ? #sections : \#sections;
}
sub subroutine {
my $param1 = shift;
my $param2 = shift;
}
sub Group {
my $self = shift;
my $section = shift;
}
sub File {
my $self = shift;
my $section = shift;
}
sub Property {
my $self = shift;
my $section = shift;
}
This is fairly trivial. We only want to keep those sub names that were originally defined in our package. Every CV (code value) has a pointer to the package where it was defined. Thanks to B, we can examine that:
use B ();
...
if (my $coderef = $self->can($symbol)) {
my $cv = B::svref_2object $coderef;
push #sections, $symbol if $cv->STASH->NAME eq __PACKAGE__;
}
# Output as wanted
That is, we perform introspection using svref_2object. This returns a Perl object representing an internal perl data structure.
If we look into a coderef, we get a B::CV object, which represents the internal CV. The STASH field in a CV points to the Stash where it was defined. As you know, a Stash is just a special hash (internally represented as a HV), so $cv->STASH returns a B::HV. The NAME field of a HV contains the fully qualified package name of the Stash if the HV is a Stash, and not a regular hash.
Now we have all the info we need, and can compare the wanted package name to the name of the stash of the coderef.
Of course, this is simplified, and you will want to recurse through #ISA for general classes.
Nobody likes polluted namespaces. Thankfully, there are modules that remove foreign symbols from the Stash, e.g. namespace::clean. This is no problem when the CVs of all subs you are calling are known at compile time.
What are you trying to do? Why does it matter how a class defined or implements a method it responds to?
Perl is a dynamic language, so that means that methods don't have to exist at all. With AUTOLOAD, a method might be perfectly fine and callable, but never show up in the symbol table. A good interface would make can work in those cases, but there might be cases where a class or an object decides to respond to that with false.
The Package::Stash module can help you find defined subroutines in a particular namespace, but as you say, they might not be defined in the same file. The methods in a class might come from an inherited class. If you care about where they come from, you're probably doing it wrong.

What is the default parameter for AUTOLOAD in Perl?

I've been playing with AUTOLOAD to create my accessors in Perl and I have encountered this confusion (I have searched google and perldoc already).
I have this code:
package Class;
sub new {
..code for constructor here.
}
sub AUTOLOAD {
my $name= shift;
print $name;
}
But when I do something like : my $a=Class->new; The autoload subroutine still executes, and prints Class=HASH(some weird number);
I thought AUTOLOAD only runs when there is an undefined method or subroutine?
And also I did this:
my $class = our $AUTOLOAD;
print $class #prints ::DESTROY
Am I right when I assumed that DESTROY is the value of $AUTOLOAD when no undefined function is passed?
Using Autoload is inherently difficult. If you want a solid object system that makes accessors for you then please use Moose, Mouse, Moo, or just loop over your fields and install the accessors yourself:
BEGIN {
my #fields = qw/foo bar baz/;
for my $field (#fields) {
no strict 'refs';
# install a closure in the package stash.
*{ __PACKAGE__ . "::" . $field } = sub {
my $self = shift;
$self->{$field} = shift if #_;
return $self->{$field};
};
}
}
If a class that can AUTOLOAD encounters an undefined method, the AUTOLOAD sub is called with the arguments of the missing sub. The fully qualified name of the requested sub is passed in the $AUTOLOAD package variable.
A typical Autoload sub would look like:
use Carp;
my %fields_allowed = map {$_ => 1} qw/foo bar baz/;
sub AUTOLOAD {
my $field = our $AUTOLOAD;
$field =~ s/.*:://; # strip the package name
$fields_allowed{$field}
or croak qq(Can't locate object method $field via package "#{[__PACKAGE__]}");
my $self = shift;
$self->{$field} = shift if #_;
return $self->{$field};
}
There remain two problems:
When the reference count of an object drops to zero, or when a thread terminates, the DESTROY method is called on the object if it provides one. We can prevent autoloading of DESTROY by providing an empty implementation: sub DESTROY {}.
We can ask any object if it can perform a certain method, like say "Good dog" if $dog->can("roll"). Therefore, we have to override can to support our autoloading. The can method is useful for safe duck typing. Every object inherits from UNIVERSAL, which provides default implementations for can and isa.
The contract of can is that it takes the name of a method. It will return undef when the object cannot perform the method, or a code reference to that method if it can. A suitable implementation would be
sub can {
my ($self, $name) = #_;
# check if it's a field of ours
if ($fields_allowed{$name}) {
return sub {
my $self = shift;
$self->{$name} = shift if #_;
return $self->{$name};
};
}
# Ask SUPER implementation of can if we can do $name
if (my $meth = $self->SUPER::can($name)) {
return $meth;
}
return; # no method found
}
We can now simplify AUTOLOAD to
sub AUTOLOAD {
my $field = our $AUTOLOAD;
$field =~ s/.*:://; # strip the package name
my $code = $self->can($field)
or croak qq(Can't locate object method $field via package "#{[__PACKAGE__]}");
goto &$code; # tail call; invisible via `caller()`.
}
This is a lot of complexity to get right. Verdict: Don't use Autoload because you think it might be less work. It never is. It is quite useful for implementing a proxy pattern, but that is a bit advanced.
I urge you to dabble around with OO basics, and the Moose object system, before diving deep into Perl's unique and strange features.

In Perl, how do I ensure that a sub is invoked as a method from methods of the same object?

I have a class that has a new method and uses that object to call method X. When I call X from the object the first value of the parameters is $self and the rest are the values I sent in. Now when I call that same method from another method on the object the first value is no longer $self and its just the values being sent in. How do I address this situation?
Sample:
my $p = TEST->new;
$p->mymethod(1,2,3); # #_ = 'self, 1, 2, 3'
but if in 'mymethod' is called by another method:
sub anothermethod{
my ($self, $a) = #_;
mymethod(1,2,3); # #_ = '1,2,3'
}
How do I write 'mymethod' so it handle both situations? Or am I fundamentally doing something incorrect?
Just as you did this:
$p->mymethod(1,2,3);
you need to be explicit about what object you are calling the method on (even within the class):
$self->mymethod(1,2,3);
This is Not A Good Idea (you ought to decide whether a subroutine is a method or not and use it in a consistent way), but in moments of weakness I have used constructions like:
sub subroutine_that_may_get_called_like_a_method {
shift if ref $_[0] eq __PACKAGE__;
my ($param1, $param2) = #_;
...
}
sub method_that_may_get_called_like_a_subroutine {
unshift #_, __PACKAGE__ if ref $_[0] ne __PACKAGE__
my ($self, $param1, $param2) = #_;
...
}
Usually I can only stare at this code for a few hours before the shame pools in my gut and I have to fix it.

Perl: When called in a method, can ref($self) ever return anything other than __PACKAGE__ or undef?

I have method in a class that I need to make sure is only called on an object instance, and not as a class method.
I will probably do something like this:
# Edit: this is terrible, don't do this, it breaks inheritance.
sub foo
{
my ($self) = #_;
if (ref($self) ne __PACKAGE__) { return; }
...do stuff
}
But I'm thinking it will be more efficient to do this:
sub foo
{
my ($self) = #_;
if (not ref($self)) { return; }
...do stuff
}
Questions:
Is it safe to assume that if ref() returns not undef that it will return the current package?
I would ideally like to go back through and do something like this in all my methods for sanity checking. Is that a bad idea?
Is there a more perlish way to do what I want?
"Use moose" is not an acceptable answer in this case. However if you are compelled to say that, please tell me how moose makes this easy or more efficient. I might want to incorporate it into my own object system.
Thanks!
EDITED to reflect that ref never returns undef, only an empty string.
EDIT 2 Here's a follow up question. Someone below suggested using:
$self->isa(__PACKAGE__)
But won't that always succeed? Unless of course the caller does something really boneheaded like:
MyClass::MyMethod($ref_to_some_other_object)
First, you should probably croak rather than silently doing nothing because, according to your specs, calling foo as a class method is a breach of contract.
Second, just checking if the first argument is a reference is enough. Your method will fail if there is inheritance involved:
#!/usr/bin/perl
package A;
use Carp;
sub new { bless {} => shift }
sub foo {
croak "I am not in " . __PACKAGE__ unless __PACKAGE__ eq ref(shift)
}
package B;
use base 'A';
package main;
$x = B->new;
$x->foo;
C:\Temp> t
I am not in A at C:\Temp\t.pl line 19
See also perldoc -f ref:
If the referenced object has been blessed into a package, then that package name is returned instead. You can think of ref as a typeof operator.
So:
sub foo {
croak "Don't call as class method" unless ref shift;
}
Finally, note that ref never returns undef.
Is it a good idea to add this check to every method? I guess one could make that argument from a design by contract view.
On the other hand, my methods assume they were called as instance methods and I only check for the possibility of a method being called as a class method if the method can provide a meaningful alternative behavior when called as such.
I cannot remember any modules which have these kinds of checks either.
By the way, instead of
sub foo {
my ($self) = #_;
you should use
sub foo {
my $self = shift;
leaving only the arguments to the method in #_ to be unpacked. Or, you should unpack all arguments in one fell swoop:
sub foo {
my ($self, $bar, $baz) = #_;
Is it safe to assume that if ref() returns not undef that it will return the current package?
No.
my $bar = Bar->new;
Package::Foo::foo($bar);
will lead to foo putting $bar into $self and ref $self will then return Bar.
And, as already noted in the earlier answers, checking for the literal package name rather than testing isa breaks inheritance anyhow.
you can also use the functional form of isa, that way you dont have to check to make sure $self is a reference. of course, the functional isa has the caveat that packages cant override isa, but i'm torn as to if that's a good or bad thing. in my own code, i usually do something like this, which i find has more useful calling semantics than UNIVERSAL::isa.
sub isa {UNIVERSAL::isa #_ > 1 ? shift : $_, #_}
.....
return unless isa $self => __PACKAGE__;
for (#objects) {
say $_->name if isa 'Package';
}