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.
Related
I can use this to include a file a.pl:
require 'a.pl';
Or I can use this:
$fn = 'a.pl';
require $fn;
However, a subroutine won't work:
sub fn { return 'a.pl'; }
require fn(); # This is a syntax error
Is there a syntax for allowing this? I noticed that I can work around the issue via
sub fn { return 'a.pl'; }
require eval("fn()");
...but that's not terribly pretty.
require(fn());
What a curious syntax error! Adding an extra parenthesis to disambiguate precedence fixes the problem. It seems that otherwise the require PACKAGE form would have precedence over require EXPR, i.e. the fn is parsed as the bareword designating the module you want to load.
The following may appear "modern" but not sufficiently correct/standard/POLA:
require fn->();
Or maybe an anonymous subroutine is more readable/efficient in some way:
my $fn = sub { return "a.pl"; } ;
require $fn->();
I have come across code with the following syntax:
$a -> mysub($b);
And after looking into it I am still struggling to figure out what it means. Any help would be greatly appreciated, thanks!
What you have encountered is object oriented perl.
it's documented in perlobj. The principle is fairly simple though - an object is a sort of super-hash, which as well as data, also includes built in code.
The advantage of this, is that your data structure 'knows what to do' with it's contents. At a basic level, that's just validate data - so you can make a hash that rejects "incorrect" input.
But it allows you to do considerably more complicated things. The real point of it is encapsulation, such that I can write a module, and you can make use of it without really having to care what's going on inside it - only the mechanisms for driving it.
So a really basic example might look like this:
#!/usr/bin/env perl
use strict;
use warnings;
package MyObject;
#define new object
sub new {
my ($class) = #_;
my $self = {};
$self->{count} = 0;
bless( $self, $class );
return $self;
}
#method within the object
sub mysub {
my ( $self, $new_count ) = #_;
$self->{count} += $new_count;
print "Internal counter: ", $self->{count}, "\n";
}
package main;
#create a new instance of `MyObject`.
my $obj = MyObject->new();
#call the method,
$obj->mysub(10);
$obj->mysub(10);
We define "class" which is a description of how the object 'works'. In this, class, we set up a subroutine called mysub - but because it's a class, we refer to it as a "method" - that is, a subroutine that is specifically tied to an object.
We create a new instance of the object (basically the same as my %newhash) and then call the methods within it. If you create multiple objects, they each hold their own internal state, just the same as it would if you created separate hashes.
Also: Don't use $a and $b as variable names. It's dirty. Both because single var names are wrong, but also because these two in particular are used for sort.
That's a method call. $a is the invocant (a class name or an object), mysub is the method name, and $b is an argument. You should proceed to read perlootut which explains all of this.
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;
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.
I simply hate how CGI::Application's accessor for the CGI object is called query.
I would like my instance classes to be able to use an accessor named cgi to get the CGI object associated with the current instance of my CGI::Application subclass.
Here is a self-contained example of what I am doing:
package My::Hello;
sub hello {
my $self =shift;
print "Hello #_\n";
}
package My::Merhaba;
use base 'My::Hello';
sub merhaba {
goto sub { shift->hello(#_) };
}
package main;
My::Merhaba->merhaba('StackOverflow');
This is working as I think it should and I cannot see any problems (say, if I wanted to inherit from My::Merhaba: Subclasses need not know anything about merhaba).
Would it have been better/more correct to write
sub merhaba {
my $self = shift;
return $self->hello(#_);
}
What are the advantages/disadvantages of using goto &NAME for the purpose of aliasing a method name? Is there a better way?
Note: If you have an urge to respond with goto is evil don't do it because this use of Perl's goto is different than what you have in mind.
Your approach with goto is the right one, because it will ensure that caller / wantarray and the like keep working properly.
I would setup the new method like this:
sub merhaba {
if (my $method = eval {$_[0]->can('hello')}) {
goto &$method
} else {
# error code here
}
}
Or if you don't want to use inheritance, you can add the new method to the existing package from your calling code:
*My::Hello::merhaba = \&My::Hello::hello;
# or you can use = My::Hello->can('hello');
then you can call:
My::Hello->merhaba('StackOverflow');
and get the desired result.
Either way would work, the inheritance route is more maintainable, but adding the method to the existing package would result in faster method calls.
Edit:
As pointed out in the comments, there are a few cases were the glob assignment will run afoul with inheritance, so if in doubt, use the first method (creating a new method in a sub package).
Michael Carman suggested combining both techniques into a self redefining function:
sub merhaba {
if (my $method = eval { $_[0]->can('hello') }) {
no warnings 'redefine';
*merhaba = $method;
goto &merhaba;
}
die "Can't make 'merhaba' an alias for 'hello'";
}
You can alias the subroutines by manipulating the symbol table:
*My::Merhaba::merhaba = \&My::Hello::hello;
Some examples can be found here.
I'm not sure what the right way is, but Adam Kennedy uses your second method (i.e. without goto) in Method::Alias (click here to go directly to the source code).
This is sort of a combination of Quick-n-Dirty with a modicum of indirection using UNIVERSAL::can.
package My::Merhaba;
use base 'My::Hello';
# ...
*merhaba = __PACKAGE__->can( 'hello' );
And you'll have a sub called "merhaba" in this package that aliases My::Hello::hello. You are simply saying that whatever this package would otherwise do under the name hello it can do under the name merhaba.
However, this is insufficient in the possibility that some code decorator might change the sub that *My::Hello::hello{CODE} points to. In that case, Method::Alias might be the appropriate way to specify a method, as molecules suggests.
However, if it is a rather well-controlled library where you control both the parent and child categories, then the method above is slimmmer.