Passing a block to a Moose method - perl

Is it somehow possible to pass blocks to Moose methods? In standard Perl, I can define a function with prototypes like this
sub fn (&) {
my $code =\&{shift #_};
$code->();
}
and then pass a block to the function without explicit sub references, i.e. fn { say "Hi there, world" }.
I think this is only possible if the subroutine is the first parameter, and as this is always $self with a Moose method, it doesn't seem possible there, forcing me to do it the slightly more explicit way:
sub wrapper {
my ($self, $code) = #_;
$code->()
}
Wrapper->wrapper(sub { say "Hi there, world" });
Now this would be a pretty convenient way to wrap some blocks, i.e. to provide some additional text or conditionally execute code or wrap an eval around some code where the error handling stays the same (e.g. eval some code and log errors, record user etc.).
If I'm not missing something, is there some semi-convenient workaround or alternative method to achieve something like this without too much line noise?

Have a look at the PerlX::MethodCallWithBlock CPAN module which contorts the Perl syntax (via the Devel::Declare module) to allow you to put a block after a method call.
For e.g.:
use 5.016;
use warnings;
use PerlX::MethodCallWithBlock;
{
package Foo;
use Moose;
sub bar {
my ($self, $code) = #_;
$code->();
}
}
Foo->bar { say "Hi there world" };
This module was released as a proof of concept. So far I've had no issues with it but YMMV.

Related

How to enable dots (.) in subroutine names?

I am working on creating a module with dynamic accessors, using autoloading. The called methods will have one or multiple dots in their names. Usage example:
use MyModule;
my $var=MyModule->a.method.get;
#MyModule::a.method.get() is now defined
It appears that the dots are illegal characters in subroutine names:
#!/usr/bin/perl
use warnings;
use strict;
sub mr.s
{
print "OK\n";
}
mr.s();
gives out
Illegal declaration of subroutine main::mr at main.pl line 5
So, how do I enable dots in subroutine names?
I understand, that at least some of the respondents might feel like discouraging usage of autoloading, as well as trying to change what is a legal subroutine name, instead providing examples of better practices. I have nothing against these kinds of answers and don't consider them any less valuable. Still, please try to provide an answer to my original question as well.
EDIT:
To clarify, the end goal is a module, where, when an undefined subroutine is called, it is dynamically defined, based on its name. To implement this I mean to use AUTOLOAD, in a way similar to how it is used in this tutorial.
You are right, that dot's are illegal in subroutine names. This has nothing to do with autoloading, they are just illegal. A dot is used for string concatenation, so your example of
MyModule->a.method.get
would actually be interpreted as
MyModule->a() . method() . get()
You can't do that, not and call them like ordinary methods [*].
Your choices are to abandon the . and use _ or something instead, or to not create accessor subs but instead have a generic get() function that takes an attribute name as a parameter.
( * Footnote: you can create such methods and call them indirectly, like so:
package Foo;
use strict;
use warnings;
BEGIN {
no strict 'refs';
*{'foo.bar'} = sub {
use strict;
return 'foo.bar value';
}
}
package main;
use strict;
use warnings;
my $method = 'foo.bar';
my $value = Foo::->$method;
but that's going to cause way more headache than you want.)
Why are you trying to use Java (or whatever) syntax? In Perl, it's written MyModule->a->get. Use that.
package MyModule;
use strict;
use warnings;
sub AUTOLOAD {
my $self = shift;
my $name = our $AUTOLOAD =~ s/^.*:://r;
my $path = ref($self) ? $self->{path}.".".$name : $name;
if (is_path_method($path)) {
return call_method($path);
} else {
return MyModule->___new(path => $path);
}
}
sub ___new {
my $class = shift;
return bless({ #_ }, $class);
}
sub DESTROY { }
Note that this will fail if try to access a proxied AUTOLOAD, can, DESTROY, DOES, import, isa, ___new or VERSION.
If you can have methods and attributes with the same name, use MyModule->a->get->(), which you can do by overloading &{}.
Per http://perldoc.perl.org/perldata.html#Identifier-parsing, I don't see that 'mr.s' validates as an identifier under either utf8 or non-utf8 source parsing. Thus, it is not a valid subroutine name.

Perl Anonymous Subroutine/Function error

I have the following piece of code: (extremely simplified for the purposes of this question, but perfectly illustrates the problem I am having)
#!/usr/bin/perl
use strict;
use warnings;
&outer;
my $connected_sub;
sub outer {
print "HELLO\n";
&$connected_sub;
$connected_sub = sub {
print "GOODBYE\n";
}
}
When run the program gives this output and error:
HELLO
Use of uninitialized value in subroutine entry at subTesting line 13.
Can't use string ("") as a subroutine ref while "strict refs" in use at subTesting.pl line 13.
Am I totally overlooking something here? I cannot understand or work out what the problem with this is.
To clarify:
Subroutine definitions happen in the compilation stage. Thus code like this will work:
foo();
sub foo { print "No need to declare me before calling!"; }
But an assignment doesn't actually happen until that line of code is called. That is why this won't work:
my $foo;
&$foo();
$foo = sub { print "Foo hasn't been set to me when you try to call me." }
I assume that what you are trying to do here is assign an anonymous sub to the variable $connected_sub. This is not a good way to do it.
What you are doing is taking an empty variable, trying to use it as a code reference, assigning a code reference to it, then exiting the sub and then declaring the variable with my. Not the best order of doing things.
What you probably want to do is return a value which can be assigned to the variable, like so:
my $connected = outer();
$connected->();
sub outer {
print "HELLO\n";
my $sub = sub { print "GOODBYE\n"; }
return $sub;
}
Using a lexical variable inside a subroutine is somewhat confusing, I think. Besides the general drawbacks of using global variables, the subroutine is also compiled before the code is executed and the variable declared.
Also, when calling a subroutine, the standard way of doing so is
name(#args);
Where #args is your argument list. Using & is old style perl, and using it has a special meaning (override prototypes). When using an anonymous sub in a variable, use the ->() notation.
The $connected_sub is not initializated. Try to assign to an anonymous sub:
my $connected_sub = sub {
print "The code you need to run\n";
}
At the definition, and drop the code after the &$connected_sub call
This is the complete example modified:
#!/usr/bin/perl
use strict;
use warnings;
my $connected_sub = sub {
print "GOODBYE\n";
};
&outer;
sub outer
{
print "HELLO\n";
&$connected_sub;
}
Looks like you're using $connected_stub before it is initialized. Try to move the initialization up, like:
$connected_sub = sub {
print "GOODBYE\n";
}
&$connected_sub;

Why does this Perl produce "Not a CODE reference?"

I need to remove a method from the Perl symbol table at runtime. I attempted to do this using undef &Square::area, which does delete the function but leaves some traces behind. Specifically, when $square->area() is called, Perl complains that it is "Not a CODE reference" instead of "Undefined subroutine &Square::area called" which is what I expect.
You might ask, "Why does it matter? You deleted the function, why would you call it?" The answer is that I'm not calling it, Perl is. Square inherits from Rectangle, and I want the inheritance chain to pass $square->area through to &Rectangle::area, but instead of skipping Square where the method doesn't exist and then falling through to Rectangle's area(), the method call dies with "Not a CODE reference."
Oddly, this appears to only happen when &Square::area was defined by typeglob assignment (e.g. *area = sub {...}). If the function is defined using the standard sub area {} approach, the code works as expected.
Also interesting, undefining the whole glob works as expected. Just not undefining the subroutine itself.
Here's a short example that illustrates the symptom, and contrasts with correct behavior:
#!/usr/bin/env perl
use strict;
use warnings;
# This generates "Not a CODE reference". Why?
sub howdy; *howdy = sub { "Howdy!\n" };
undef &howdy;
eval { howdy };
print $#;
# Undefined subroutine &main::hi called (as expected)
sub hi { "Hi!\n" }
undef &hi;
eval { hi };
print $#;
# Undefined subroutine &main::hello called (as expected)
sub hello; *hello = sub { "Hello!\n" };
undef *hello;
eval { hello };
print $#;
Update: I have since solved this problem using Package::Stash (thanks #Ether), but I'm still confused by why it's happening in the first place. perldoc perlmod says:
package main;
sub Some_package::foo { ... } # &foo defined in Some_package
This is just a shorthand for a typeglob assignment at compile time:
BEGIN { *Some_package::foo = sub { ... } }
But it appears that it isn't just shorthand, because the two cause different behavior after undefining the function. I'd appreciate if someone could tell me whether this is a case of (1) incorrect docs, (2) bug in perl, or (3) PEBCAK.
Manipulating symbol table references yourself is bound to get you into trouble, as there are lots of little fiddly things that are hard to get right. Fortunately there is a module that does all the heavy lifting for you, Package::Stash -- so just call its methods add_package_symbol and remove_package_symbol as needed.
Another good method installer that you may want to check out is Sub::Install -- especially nice if you want to generate lots of similar functions.
As to why your approach is not correct, let's take a look at the symbol table after deleting the code reference:
sub foo { "foo!\n"}
sub howdy; *howdy = sub { "Howdy!\n" };
undef &howdy;
eval { howdy };
print $#;
use Data::Dumper;
no strict 'refs';
print Dumper(\%{"main::"});
prints (abridged):
$VAR1 = {
'howdy' => *::howdy,
'foo' => *::foo,
};
As you can see, the 'howdy' slot is still present - undefining &howdy doesn't actually do anything enough. You need to explicitly remove the glob slot, *howdy.
The reason it happens is precisely because you assigned a typeglob.
When you delete the CODE symbol, the rest of typeglob is still lingering, so when you try to execute howdy it will point to the non-CODE piece of typeglob.

How do you replace a method of a Moose object at runtime?

Is it possible to replace a method of a Moose object at runtime ?
By looking at the source code of Class::MOP::Method (which Moose::Meta::Method inherits from) I concluded that by doing
$method->{body} = sub{ my stuff }
I would be able to replace at runtime a method of an object.
I can get the method using
$object->meta->find_method_by_name(<method_name>);
However, this didn't quite work out.
Is it conceivable to modify methods at run time? And, what is the way to do it with Moose?
Moose or not, that does not sound like a good idea.
Instead, design your object to have an accessor for the method. For example, users of your class can use My::Frobnicator->frobnicator->() to get and invoke the frobnicator method and use My::Frobnicator->frobnicator(sub { } ) to set it.
Sinan's idea is a great start.
But with an little extra tweak, you can make using your method accessor just like using a normal method.
#!/usr/bin/perl
use strict;
use warnings;
use Carp;
my $f = Frob->new;
$f->frob(
sub {
my $self = shift;
print "$self was frobbed\n";
print Carp::longmess('frob')
}
);
print "\nCall frob as normal sub\n";
$f->frobit;
print "\nGoto frob\n";
$f->goto_frob;
BEGIN {
package Frob;
use Moose;
has 'frob' => (
is => 'rw',
isa => 'CodeRef',
);
sub frobit {
&{$_[0]->frob};
}
sub goto_frob {
goto $_[0]->frob;
}
}
The two methods in Frob are very similar.
frobit passes all arguments, including the invocant to the code ref.
goto_frob passes all arguments, including the invocant to the code ref, and replaces goto_frob's stack frame with the code refs.
Which to use depends on what you want in the stack.
Regarding munging the body storage of a Class::MOP::Method object, like so $method->{body} = sub { 'foo' }:
It's never a good idea to violate encapsulation when you are doing OOP. Especially not when you are working with complex object systems like Moose and Class::MOP. It's asking for trouble. Sometimes, there is no other way to get what you want, but even then, violating encapsulation is still a bad idea.
Using the previously mentioned MooseX::SingletonMethod you can replace an objects method.
For example:
{
package Foo;
use MooseX::SingletonMethod;
sub foo { say 'bar' };
}
my $bar = Foo->new;
my $baz = Foo->new;
# replace foo method just in $baz object
$baz->add_singleton_method( foo => sub { say 'baz' } );
$bar->foo; # => bar
$baz->foo; # => baz
Also see this SO answer to What should I do with an object that should no longer be used in Perl?, which shows how this can be achieved using Moose roles.
/I3az/

How can I override Perl functions, enabling multiple overrides?

some time ago, I asked This question about overriding building perl functions.
How do I do this in a way that allows multiple overrides? The following code yields an infinite recursion.
What's the proper way to do this? If I redefine a function, I don't want to step on someone else's redefinition.
package first;
my $orig_system1;
sub mysystem {
my #args = #_;
print("in first mysystem\n");
return &{$orig_system1}(#args);
}
BEGIN {
if (defined(my $orig = \&CORE::GLOBAL::system)) {
$orig_system1 = $orig;
*CORE::GLOBAL::system = \&first::mysystem;
printf("first defined\n");
} else {
printf("no orig for first\n");
}
}
package main;
system("echo hello world");
The proper way to do it is not to do it. Find some other way to accomplish what you're doing. This technique has all the problems of a global variable, squared. Unless you get your rewrite of the function exactly right, you could break all sorts of code you never even knew existed. And while you might be polite in not blowing over an existing override, somebody else probably will not be.
Overriding system is particularly touchy because it does not have a proper prototype. This is because it does things not expressible in the prototype system. This means your override cannot do some things that system can. Namely...
system {$program} #args;
This is a valid way to call system, though you need to read the exec docs to do it. You might think "oh, well I just won't do that then", but if any module that you use does it, or any module it uses does it, then you're out of luck.
That said, there's little different from overriding any other function politely. You have to trap the existing function and be sure you call it in your new one. Whether you do it before or after is up to you.
The problem in your code is that the proper way to check if a function is defined is defined &function. Taking a code ref, even of an undefined function, will always return a true code ref. I'm not sure why, maybe its like how \undef will return a scalar ref. Why calling this code ref is causing mysystem() to go infinitely recursive is anyone's guess.
There's an additional complexity in that you can't take a reference to a core function. \&CORE::system doesn't do what you mean. Nor can you get at it with a symbolic reference. So if you want to call CORE::system or an existing override depending on which is defined you can't just assign one or the other to a code ref. You have to split your logic.
Here is one way to do it.
package first;
use strict;
use warnings;
sub override_system {
my $after = shift;
my $code;
if( defined &CORE::GLOBAL::system ) {
my $original = \&CORE::GLOBAL::system;
$code = sub {
my $exit = $original->(#_);
return $after->($exit, #_);
};
}
else {
$code = sub {
my $exit = CORE::system(#_);
return $after->($exit, #_);
};
}
no warnings 'redefine';
*CORE::GLOBAL::system = $code;
}
sub mysystem {
my($exit, #args) = #_;
print("in first mysystem, got $exit and #args\n");
}
BEGIN { override_system(\&mysystem) }
package main;
system("echo hello world");
Note that I've changed mysystem() to merely be a hook that runs after the real system. It gets all the arguments and the exit code, and it can change the exit code, but it doesn't change what system() actually does. Adding before/after hooks is the only thing you can do if you want to honor an existing override. Its quite a bit safer anyway. The mess of overriding system is now in a subroutine to keep BEGIN from getting too cluttered.
You should be able to modify this for your needs.