Why doesn't Perl's SUPER call use the arrow method? - perl

I noticed that when you call a superclass's methods, you need to do something like this :
my $self = $class->SUPER::new();
Why isn't that:
my $self = $class->SUPER->new();

I suspect because $class->SUPER->new() would normally be the same as $class->SUPER()->new(). But there isn't a $class->SUPER() function, and its not clear what that would return.
On the other hand, $class->Foo::Bar has always been a valid way to call a method directly by full name, so making a special package-like thing — SUPER — fits in better. (I suspect that you could actually implement SUPER as a package, and maybe it historically was, I don't know)
PS: Take a look at the mro package, and $self->next::method. Also, take a look at Moose if you're going to do serious OO work in Perl.

In short, SUPER isn't a method. It's a virtual package. It's documented in perlobj under the "Method Invocation" section.
Note, however, that SUPER bases itself on the current package, not the package of the instance you used it with.

Method calls have a number of forms:
Calls method, possibly inherited:
->method()
Explicitly calls sub Package::method, whether that's in the inheritance tree or not:
->Package::method()
Explicitly calls the referred-to sub, whether that's in the inheritance tree or not:
->$coderef()
Calls the method that would have been called by __PACKAGE__->method() if there were no sub method in __PACKAGE__ (N.B. the class or object on the left of -> is irrelevant):
->SUPER::method()
Any of the above, depending on the contents of $method:
->$method()
(Legal even under use strict;.)
While the first form is the most common, it's worth learning about the others and how they work.

To add to what derobert said:
You're calling 'new' in the 'SUPER' namespace but passing it the object (or string), '$class'.
You don't have to use SUPER, as you can give the full package name of the parent (useful in cases of diamond inheritance):
sub init {
my $self = shift;
$self->ParentClass1::init();
$self->ParentClass2::init();
}

Related

Make package both Functional and OO

I've seen CPAN Perl modules that can be used in a functional or OO way. I usually write OO and Functional packages depending on what I need, but I'm still not how write modules that can used both ways.
Could somebody give me a simple example of a package that can be used in functional and/or OO way? I'm obviously interested in the pieces that allows the package be used both ways.
Thank you
A core example is File::Spec, which has a File::Spec::Functions wrapper. It's not so much object oriented but it does use the object oriented principle of inheritance, so its main API uses method calls, but it doesn't need to keep any state.
use strict;
use warnings;
use File::Spec;
use File::Spec::Functions 'catfile';
print File::Spec->catfile('/', 'foo', 'bar');
print catfile '/', 'foo', 'bar';
Another example is Sereal, whose encoder and decoder can be used both as objects or via exported functions which wrap them.
use strict;
use warnings;
use Sereal::Encoder 'encode_sereal';
my $data = {foo => 'bar'};
my $encoded = Sereal::Encoder->new->encode($data);
my $encoded = encode_sereal $data;
Sereal aside, it's usually good organizational practice to keep your object classes and your exporting modules separate. Especially don't try to have the same function be callable as a method or an exported function; the primary issue is that it's indistinguishable from the subroutine itself whether it was called as $obj->function('foo') or function($obj, 'foo'). As #choroba noted, CGI.pm tries to do this and it's a mess.
My WiringPi::API distribution is written in such a way. Note that in this case here, there's no state saving required, so if keeping state is a necessity, this way of doing it won't work as-is.
You can use it functionally:
use WiringPi::API qw(:all)
setup_gpio();
...
Or use its Object Oriented interface:
use WiringPi::API;
my $api = WiringPi::API->new;
$api->setup_gpio();
...
For functional, I use #EXPORT_OK, so that the user's namespace isn't polluted unnecessarily:
our #EXPORT_OK;
#EXPORT_OK = (#wpi_c_functions, #wpi_perl_functions);
our %EXPORT_TAGS;
$EXPORT_TAGS{wiringPi} = [#wpi_c_functions];
$EXPORT_TAGS{perl} = [#wpi_perl_functions];
$EXPORT_TAGS{all} = [#wpi_c_functions, #wpi_perl_functions];
...and a few example functions/methods. Essentially, we check the number of parameters coming in, and if there's an extra one (which would be the class/object), we manually just shift it out:
sub serial_open {
shift if #_ > 2;
my ($dev_ptr, $baud) = #_;
my $fd = serialOpen($dev_ptr, $baud);
die "could not open serial device $dev_ptr\n" if $fd == -1;
return $fd;
}
sub serial_close {
shift if #_ > 1;
my ($fd) = #_;
serialClose($fd);
}
sub serial_flush {
shift if #_ > 1;
my ($fd) = #_;
serialFlush($fd);
}
Typically I would do some parameter checking to ensure that we're shifting off the correct thing, but in testing, it was faster to allow the back end C/XS code worry about that for me.
As stated, there are a number of modules that do this and some have been named. A good practice is to write a separate module for the functional interface, that uses the class and exports its (select) functions.
But it is quite possible to have both interfaces in one package, with same method/function names, if there is a specific need for that. See the section at the end for one very specific and rare use case that wouldn't be handled by the following basic example, and for how to resolve it.
Here is a basic package that has both interfaces
package Duplicious; # having interfaces to two paradigms may be confusing
use warnings;
use strict;
use feature 'say';
use Scalar::Util qw(blessed);
use Exporter qw(import);
our #EXPORT_OK = qw(f1);
my $obj_cache; # so repeated function calls don't run constructor
sub new {
my ($class, %args) = #_;
return bless { }, $class;
}
sub f1 {
say "\targs in f1: ", join ', ', #_; # see how we are called
my $self = shift;
# Functional interface
# (first argument not object or class name in this or derived class)
if ( not ( (blessed($self) and $self->isa(__PACKAGE__))
or (not ref $self and $self->isa(__PACKAGE__)) ) )
{
return ($obj_cache || __PACKAGE__->new)->f1($self, #_);
}
# Now method definition goes
# ...
return 23;
}
1;
The caller
use warnings; # DEMO only --
use strict; # Please don't mix uses in the same program
use feature 'say';
use Duplicious qw(f1);
my $obj = Duplicious->new;
say "Call as class method: ";
Duplicious->f1("called as class method");
say "Call as method:";
my $ret_meth = $obj->f1({}, "called as method");
say "\nCall as function:";
my $ret_func = f1({}, "called as function");
Output
Call as class method:
args in f1: Duplicious, called as class method
Call as method:
args in f1: Duplicious=HASH(0x21b1b48), HASH(0x21a8738), called as method
Call as function:
args in f1: HASH(0x21a8720), called as function
args in f1: Duplicious=HASH(0x218ba68), HASH(0x21a8720), called as function
The function call dispatches to the method, thus two lines (note arguments).
I find it in principle awkward to use Exporter in a module that defines a class (but I am not aware of any actual problems with doing it); it results in a potentially confusing interface. This on its own is a good reason to separate interfaces so that the functional one has to load a specific module.
There is also one detail that requires attention. The method call
($obj_cache || __PACKAGE__->new)->f1(...)
uses the cached $obj_cache (if this sub has been called already) to make the call. Thus the object's state is kept, that may or not have been manipulated in the previous calls to f1.
That is rather non-trivial in a call meant to be used in a non object-oriented context and should be carefully investigated. If there are issues just drop that cacheing or expand it into a full if statement where the state can be reset as needed.
These two uses should absolutely not be mixed in the same program.
To test with a derived class I use the minimal
package NextDupl;
use warnings;
use strict;
use feature 'say';
use parent 'Duplicious';
1;
and add to the main program above the following
# Test with a subclass (derived, inherited class)
my $inh = NextDupl->new;
say "\nCall as method of derived class";
$inh->f1("called as method of derived class");
# Retrieve with UNIVERSAL::can() from parent to use by subclass
my $rc_orig = Duplicious->can('f1');
say "\nCall via coderef pulled from parent, by derived class";
NextDupl->$rc_orig("called via coderef of parent by derived class");
The additional output is
Call as method of derived class
args in f1: NextDupl=HASH(0x11ac720), called as method of derived class
Call via coderef pulled from parent, by derived class
args in f1: NextDupl, called via coderef of parent by derived clas
This incorporates a test using UNIVERSAL::can, as it came up in a comment.
There is one specific limitation (that I am aware of), raised and discussed in comments.
Imagine that we write a method that takes an object (or a class name) as its first argument, so to be invoked as ->func($obj); further – and this is what matters – this method allows any class as it works in a way that doesn't care what class it has. This would be very particular, but it is possible and it raises the following problem.
The function call corresponding to this method would be func($obj), and when $obj happens to be in the hierarchy of this class that would result in the method call ->func(), incorrectly.
There is no way to disambiguate this in the code that decides on whether
it's called as a function or as a method, since all it does is it looks at the first argument. If it's an object/class in our own hierarchy it decides that this was a method call on that object (or a class method call), and in this particular case that is wrong.
There are two simple ways, and possibly another one, for the module's author to settle this
Do not provide the functional interface for this highly specific method
Give it a separate (clearly related) name
The if condition that decides how we are called, by checking the first argument, is canned but still written for every method that has that interface. So in this method check one more argument: if the first one is object/class of this class and the next is (any) object/class then it's a method call. This does not work if that second argument is optional.
All this is completely reasonable. In a class that exercises its defining trait, to have and use data ("attributes"), there will likely be methods that cannot be translated into function calls. This is because a single program should only use one interface, and with functions there is no state so methods that rely on it won't fly. (Use of a cached object for this is highly treacherous.)
So one will always have to decide carefully about the interface, and to pick and choose.
Thanks to Grinnz for comments.
Note that there is a completely different paradigm of "functional programming," and the title leaves that a little unclear. All this is about the functional interface in a procedural approach.

Setting MooseX::Method::Signatures defaults to an instance variable

I have a set of methods where I would like the caller to be able to override a value, or it defaults to the instance variable.
So what I keep trying to do is:
method foo( Str :$blah = $self->blah ) {
#doStuff
}
which throws a parsing error so I end up doing this everywhere
method foo( Str :$blah? ) {
$blah = $self->blah unless defined $blah;
#doStuff
}
Not horrendous, but seems silly when MooseX::Method::Signatures supports the default concept and has fixed all my other standard 'start of method' lines.
Invariably when I'm trying to do something like this and I can't find anyone else on the web who's run into the same problems, I'm approaching the problem the wrong way. It seems like I might be trying to jam a functional program into a oo layout, rather than actual oo as the methods are more helper functions for calling externally rather than methods operating on the object. So just checking if I'm just defining it incorrectly or if what I'm doing is "dumb" or just not supported by Parse::Method::Signatures.
AFAIK The Signatures module hooks itself into the Perl parser and injects some code to handle the prototypes. It is remarkable that this works.
That said, using non-constant values as defaults could have issues. And there may be scenarios where calling some code to prepopulate a value could wreak havoc. Specifically, should the code that prepopulates the value should only be called if no value for the argument is given, or should it be always called? What should we do with side effects? What should the caller be? If I have a global $self object, shouldn't that receive the method call, as the scoping rules clearly dictate this? (As our $x=5; my $x=$x; is valid, but just my $x=$x is not). Even better, what would happen if the default value population method call would call the same method, but again without a value for the optional parameter?
You can always fall back to old-school optional parameters:
sub foo {
my ($self, $blah) = #_;
# something like my ($self, $blah) = (#_, $self->blah); wouldn't work, of course.
$blah //= $self->blah; # nicer than old `unless defined`
...;
}
or, in this case:
method foo (:$blah?) {
$blah //= $self->blah
}
I find this use of the defined-or operator quite enjoyable.

Correct way to instantiate a Moose object from another Moose object?

What is the correct way to create an instance from another Moose object? In practice I've seen this done numerous ways:
$obj->meta->name->new()
$obj->new() ## which has been deprecated and undeprecated
(blessed $obj)->new()
-- and, its bastard variant: (ref $obj)->new()
$obj->meta->new_object()
And, then what if you have traits? Is there a transparent way to support that? Do any of these work with anonymous classes?
Of your choices, $obj->meta->name->new() or (blessed $obj)->new() are both the safest.
The way traits are implemented, you create an anonymous subclass and apply the roles to that subclass and rebless the instance into that subclass. This means that either of these solutions will work fine with traits. Perl lacks truly anonymous subclasses (every package has to have namespace), Moose works around this by creating a name in a generic namespace for anonymous classes.
If you'd taken a second to try some example code, you'd see this in action.
$perl -Moose -E'with q[MooseX::Traits];
package Role; use Moose::Role;
package main; say Class->with_traits(q[Role])->new->meta->name'
MooseX::Traits::__ANON__::SERIAL::1
Hope that helps.

How can I access a method of the consumer class inside a method created at runtime in a method of the parameterized role using Moose with Perl?

I define a method inside a parametrized role that needs to create a new class at run time
using Moose::Meta::Class->create and apply that exact parametrized role to it. I am also making a new method for that role using
$new_class->meta->add_method( some_name => sub {
my ($self) = #_;
...
})
inside the sub {...} I want to access a method of the consumer class and use it for something, I have tried using $self->get_method, it didn't work, how do I do this?
Please notice that the $self inside the sub above is MooseX::Role::Parameterized::Meta::Role::Parameterizable
I also have another question, if I do this:
my $object = Moose::Meta::Class->create(
"some_type",
);
Why isn't $object of type some_type and it's some ugly MooseX::Role::Parameterized::Meta::Role::Parameterizable and how do I get to the object of type some_type?
To answer your second question, the reason is because Perl's OO doesn't allow you to add a method to just one instance of a class, so Moose has to fake it by creating a subclass with the extra method and reblessing the unique object into that subclass.
Note that, if you are doing things correctly and doing your introspection with isa, has, and/or does rather than by trying to rely on the name of the object's blessed package, this doesn't matter. The object still isa some_type, has all of some_type's attributes, and does all of some_type's roles even though it's now blessed into a package with an ugly auto-generated name.
It sounds like your underlying problem is nearly exactly what I described at this question: from within the role definition, you need to get at the class (and its meta-class) of the object or class the role is being applied to. This isn't possible from within normal roles, but it's possible through parameterized roles.
I'm not quite sure what you're trying to do here. Let's assume you have
my $new_class = Moose::Meta::Class->create('FooBar');
then $new_class is the meta object for FooBar. So, if you want to add a method to FooBar you would say
$new_class->add_method(foo => sub { … });
which would basically be the same as
FooBar->meta->add_method(foo => sub { … });
You should also probably use find_meta() from Moose::Util. This will return the correct meta object (if there is one) even if your class doesn't have a meta method or it uses it for something else.
As said, I'm not sure this answers your question.

Do I need to use a class to use its methods in my subclass in Perl?

Alrighty, coding in Perl and just had a quick question. I have class created called SubtitleSite which is basically an abstraction, and a class called podnapisi that inherits SubtitleSite like this:
#ISA = qw(SubtitleSite);
My question is, do I have to use:
use SubtitleSite;
in order to have access to all the methods in SubtitleSite?
Yes, but most of the time you're better off not messing with #ISA directly. Just use parent qw(SubtitlesSite);, it will load SubtilteSite for you and add it to #ISA.
Yes.
Some more info can be found here:
http://www.troubleshooters.com/codecorn/littperl/perloop.htm#PerlInheritance
YES.
Otherwise the symbols defined in SubtitleSite are undefined in podnapisi.
In order to access the methods, you'd either have to inherit from it, or delegate to an object of it's type.
If you are constructing an object in your child class, you can just call methods on yourself and they will be found through the magic of inheritance (see perldoc perlobj for more about SUPER):
sub foo
{
my $this = shift;
$this->method_on_parent; # this works!
$this->SUPER::foo; # this works too
}
However if these classes are only library functions that don't use OO, you have to tell Perl explicitly where to find the function:
ParentClass::function; # use the class name explicitly