Hello I am trying to understand Perl better. I come from Ruby and trying to wrap my head around Perl for fun. Let's say I have this code block here.
$self->doSomething(
{ record => $record,
listing => [ $foo, $bar, $baz ],
passedargs => { something => $val, another => $val2 },
}
);
What exactly is defined as $args? My thought process from reading Perl docs is something like my ($self, $args) = #_; Meaning everything within the doSomething block is considered $args and if I wanted to access it. I would my $args = #_[0];
Just curious if I am thinking about this correctly? if not care to explain?
Since you are invoking doSomething as a method call, the first argument will be the object you are calling the method on (i.e. that which is on the left hand side of the arrow operator: $self).
The second argument will be the hashref you are passing between the ( and the ).
You access a particular member of the hashref just as you would for any other hashref.
sub doSomething {
my ($self, $args) = #_;
my $record = $args->{record};
Related
I'm getting this error and cannot understand why this happens. It happens when I jump to another subroutine. Perhaps there is something I need to understand about Mojolicious on why this happens.
Here is the source code of my program:
#!/usr/bin/perl
use Mojolicious::Lite;
get '/' => sub { &start_home; };
app->start;
sub start_home {
my $d = shift;
my $something = $d->param('something');
### Do things with $something.... etc.. etc..
&go_somewhere_else; ### Go somewhere else
}
sub go_somewhere_else {
my $c = shift;
$c->render(text => "Hello World!");
### End of program
}
I am passing a value on to the renderer and there is a value - Why would it say it is undefined? My understanding is that this only happens if you jump to a subroutine and try to render output.
My operating system is Windows and I am using Strawberry Perl.
You need to pass the context object $c/$d to your second function. The undefined value is your $c in go_somewhere_else, because you call it without a parameter.
Initially, to make it work, do this.
sub start_home {
my $d = shift;
my $something = $d->param('something');
go_somewhere_else($d);
}
You are now passing the context, which you named $d (that's not the conventional name), to the other function, and the warning will go away.
That's because the form &subname; without parenthesis () makes #_ (that's the list of arguments to the function) available inside of go_somewhere_else, but because you shifted $d off, #_ is now empty, and hence your $c inside go_somewhere_else is undef.
Alternatively, you could also change the shift to an assignment with #_. But please, don't do that!
sub start_home {
my ( $d ) = #_;
my $something = $d->param('something');
&go_somewhere_else;
}
There are more things odd to the point of almost wrong here.
get '/' => sub { &start_home; };
You are currying the the start_home function, but you are not actually adding another parameter. I explained above why this works. But it's not great. In fact, it's confusing and complicated.
Instead, you should use a code reference for the route.
get '/' => \&start_home;
Inside of start_home, you should call your context $c as is the convention. You should also not use the ampersand & notation for calling functions. That changes the behavior in a way you most certainly do not want.
sub start_home {
my $c = shift;
my $something = $c->param('something');
# ...
go_somewhere_else($c);
}
To learn more about how function calls work in Perl, refer to perlsub.
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.
I have a perl script (simplified) like so:
my $dh = Stats::Datahandler->new(); ### homebrew module
my %url_map = (
'/(article|blog)/' => \$dh->articleDataHandler,
'/video/' => \$dh->nullDataHandler,
);
Essentially, I'm going to loop through %url_map, and if the current URL matches a key, I want to call the function pointed to by the value of that key:
foreach my $key (keys %url_map) {
if ($url =~ m{$key}) {
$url_map{$key}($url, $visits, $idsite);
$mapped = 1;
last;
}
}
But I'm getting the message:
Can't use string ("/article/") as a subroutine ref while "strict refs" in use at ./test.pl line 236.
Line 236 happens to be the line $url_map{$key}($url, $visits, $idsite);.
I've done similar things in the past, but I'm usually doing it without parameters to the function, and without using a module.
Since this is being answered here despite being a dup, I may as well post the right answer:
What you need to do is store a code reference as the values in your hash. To get a code reference to a method, you can use the UNIVERSAL::can method of all objects. However, this is not enough as the method needs to be passed an invocant. So it is clearest to skip ->can and just write it this way:
my %url_map = (
'/(article|blog)/' => sub {$dh->articleDataHandler(#_)},
'/video/' => sub {$dh->nullDataHandler(#_)},
);
This technique will store code references in the hash that when called with arguments, will in turn call the appropriate methods with those arguments.
This answer omits an important consideration, and that is making sure that caller works correctly in the methods. If you need this, please see the question I linked to above:
How to take code reference to constructor?
You're overthinking the problem. Figure out the string between the two forward slashes, then look up the method name (not reference) in a hash. You can use a scalar variable as a method name in Perl; the value becomes the method you actually call:
%url_map = (
'foo' => 'foo_method',
);
my( $type ) = $url =~ m|\A/(.*?)/|;
my $method = $url_map{$type} or die '...';
$dh->$method( #args );
Try to get rid of any loops where most of the iterations are useless to you. :)
my previous answer, which I don't like even though it's closer to the problem
You can get a reference to a method on a particular object with can (unless you've implemented it yourself to do otherwise):
my $dh = Stats::Datahandler->new(); ### homebrew module
my %url_map = (
'/(article|blog)/' => $dh->can( 'articleDataHandler' ),
'/video/' => $dh->can( 'nullDataHandler' ),
);
The way you have calls the method and takes a reference to the result. That's not what you want for deferred action.
Now, once you have that, you call it as a normal subroutine dereference, not a method call. It already knows its object:
BEGIN {
package Foo;
sub new { bless {}, $_[0] }
sub cat { print "cat is $_[0]!\n"; }
sub dog { print "dog is $_[0]!\n"; }
}
my $foo = Foo->new;
my %hash = (
'cat' => $foo->can( 'cat' ),
'dog' => $foo->can( 'dog' ),
);
my #tries = qw( cat dog catbird dogberg dogberry );
foreach my $try ( #tries ) {
print "Trying $try\n";
foreach my $key ( keys %hash ) {
print "\tTrying $key\n";
if ($try =~ m{$key}) {
$hash{$key}->($try);
last;
}
}
}
The best way to handle this is to wrap your method calls in an anonymous subroutine, which you can invoke later. You can also use the qr operator to store proper regexes to avoid the awkwardness of interpolating patterns into things. For example,
my #url_map = (
{ regex => qr{/(article|blog)/},
method => sub { $dh->articleDataHandler }
},
{ regex => qr{/video/},
method => sub { $dh->nullDataHandler }
}
);
Then run through it like this:
foreach my $map( #url_map ) {
if ( $url =~ $map->{regex} ) {
$map->{method}->();
$mapped = 1;
last;
}
}
This approach uses an array of hashes rather than a flat hash, so each regex can be associated with an anonymous sub ref that contains the code to execute. The ->() syntax dereferences the sub ref and invokes it. You can also pass parameters to the sub ref and they'll be visible in #_ within the sub's block. You can use this to invoke the method with parameters if you want.
What is the "best" way to use "isa()" reliably? In other words, so it works correctly on any value, not just an object.
By "best", I mean lack of un-handled corner cases as well as lack of potential performance issues, so this is not a subjective question.
This question mentions two approaches that seem reliable (please note that the old style UNIVERSAL::isa() should not be used, with reasons well documented in the answers to that Q):
eval { $x->isa("Class") }
#and check $# in case $x was not an object, in case $x was not an object
use Scalar::Util 'blessed';
blessed $x && $x ->isa($class);
The first one uses eval, the second uses B:: (at least for non-XS flavor of Scalar::Util).
The first does not seem to work correctly if $x is a scalar containing a class name, as illustrated below, so I'm leaning towards #2 (using blessed) unless somoene indicates a good reason not to.
$ perl5.8 -e '{use IO::Handle;$x="IO::Handle";
eval {$is = $x->isa("IO::Handle")}; print "$is:$#\n";}'
1:
Are there any objective reasons to pick one of these two approaches (or a 3rd one i'm not aware of) such as performance, not handling some special case, etc...?
The Scalar::Util implementation is categorically better. It avoids the overhead of the eval {} which always results in the setting of an additional variable.
perl -we'$#=q[foo]; eval {}; print $#'
The Scalar::Util implementation is easier to read (it doesn't die for a reason that is unknown to the code). If the eval fails too, I believe what happens is you have walk backwards in the tree to the state prior to the eval -- this is how resetting state is achieved. This comes with additional overhead on failure.
Benchmarks
Not an object at all
Rate eval su
eval 256410/s -- -88%
su 2222222/s 767% --
Object passing isa check
Rate su eval
su 1030928/s -- -16%
eval 1234568/s 20% --
Object failing isa check
Rate su eval
su 826446/s -- -9%
eval 909091/s 10% --
Test code:
use strict;
use warnings;
use Benchmark;
use Scalar::Util;
package Foo;
Benchmark::cmpthese(
1_000_000
, {
eval => sub{ eval{ $a->isa(__PACKAGE__) } }
, su => sub { Scalar::Util::blessed $a && $a->isa(__PACKAGE__) }
}
);
package Bar;
$a = bless {};
Benchmark::cmpthese(
1_000_000
, {
eval => sub{ eval{ $a->isa(__PACKAGE__)} }
, su => sub { Scalar::Util::blessed $a && $a->isa(__PACKAGE__) }
}
);
package Baz;
$a = bless {};
Benchmark::cmpthese(
1_000_000
, {
eval => sub{ eval{ $a->isa('duck')} }
, su => sub { Scalar::Util::blessed $a && $a->isa( 'duck' ) }
}
);
I used This is perl, v5.10.1 (*) built for i486-linux-gnu-thread-multi, and Scalar::Util, 1.21
You can wrap the safety checks in a scalar and then use the scalar as a method to keep things clean:
use Scalar::Util 'blessed';
my $isa = sub {blessed $_[0] and $_[0]->isa($_[1])};
my $obj;
if ($obj->$isa('object')) { ... } # returns false instead of throwing an error
$obj = {};
if ($obj->$isa('object')) { ... } # returns false as well
bless $obj => 'object';
if ($obj->$isa('object')) { say "we got an object" }
Note that $obj->$isa(...) is just a different spelling of $isa->($obj, ...) so no method call actually takes place (which is why it avoids throwing any errors).
And here is some code that will allow you to call isa on anything and then inspect the result (inspired by Axeman's answer):
{package ISA::Helper;
use Scalar::Util;
sub new {
my ($class, $obj, $type) = #_;
my $blessed = Scalar::Util::blessed $obj;
bless {
type => $type,
obj => $obj,
blessed => $blessed,
isa => $blessed && $obj->isa($type)
} => $class
}
sub blessed {$_[0]{blessed}}
sub type {$_[0]{isa}}
sub ref {ref $_[0]{obj}}
sub defined {defined $_[0]{obj}}
use overload fallback => 1,
bool => sub {$_[0]{isa}};
sub explain {
my $self = shift;
$self->type ? "object is a $$self{type}" :
$self->blessed ? "object is a $$self{blessed} not a $$self{type}" :
$self->ref ? "object is a reference, but is not blessed" :
$self->defined ? "object is defined, but not a reference"
: "object is not defined"
}
}
my $isa = sub {ISA::Helper->new(#_)};
By placing the code reference in a scalar, it can be called on anything without error:
my #items = (
undef,
5,
'five',
\'ref',
bless( {} => 'Other::Pkg'),
bless( {} => 'My::Obj'),
);
for (#items) {
if (my $ok = $_->$isa('My::Obj')) {
print 'ok: ', $ok->explain, "\n";
} else {
print 'error: ', $ok->explain, "\n";
}
}
print undef->$isa('anything?')->explain, "\n";
my $obj = bless {} => 'Obj';
print $obj->$isa('Obj'), "\n";
my $ref = {};
if (my $reason = $ref->$isa('Object')) {
say "all is well"
} else {
given ($reason) {
when (not $_->defined) {say "not defined"}
when (not $_->ref) {say "not a reference"}
when (not $_->blessed) {say "not a blessed reference"}
when (not $_->type) {say "not correct type"}
}
}
this prints:
error: object is not defined
error: object is defined, but not a reference
error: object is defined, but not a reference
error: object is a reference, but is not blessed
error: object is a Other::Pkg not a My::Obj
ok: object is a My::Obj
object is not defined
1
not a blessed reference
If anyone thinks this is actually useful, let me know, and I will put it up on CPAN.
Here's an update for 2020. Perl v5.32 has the isa operator, also known as the class infix operator. It handles the case where the left-hand argument is not an object it returns false instead of blowing up:
use v5.32;
if( $something isa 'Animal' ) { ... }
This might sound a little bit harsh to Perl, but neither one of these is ideal. Both cover up the fact that objects are a tack on to Perl. The blessed idiom is wordy and contains more than a couple simple pieces.
blessed( $object ) && object->isa( 'Class' )
I would prefer something more like this:
object_isa( $object, 'Class' )
There is no logical operation to get wrong, and most of the unfit uses will be weeded out by the compiler. (Quotes not closed, no comma, parens not closed, calling object_isa instead...)
It would take undefined scalars, simple scalars (unless they are a classname that is a Class), unblessed references, and blessed references that do not extend 'Class' and tell you that no, they are not Class objects. Unless we want to go the route of autobox-ing everything, we're going to need a function that tells us simply.
Perhaps there might be a third parameter for $how_close, but there could also be something like this:
if ( my $ranking = object_isa( $object, 'Class' )) {
...
}
else {
given ( $ranking ) {
when ( NOT_TYPE ) { ... }
when ( NOT_BLESSED ) { ... }
when ( NOT_REF ) { ... }
when ( NOT_DEFINED ) { ... }
}
}
About the only way I can see that we could return this many unique falses is if $ranking was blessed into a class that overloaded the boolean operator to return false unless the function returned the one value indicating an ISA relationship.
However, it could have a few members: EXACTLY, INHERITS, IMPLEMENTS, AGGREGATES or even MOCKS
I get tired of typing this too:
$object->can( 'DOES' ) && $object->DOES( 'role' )
because I try to implement the future-facing DOES in lesser perls (on the idea that people might frown on my polluting UNIVERSAL) on them.
I hava a perl subroutine where i would like to pass parameters as a hash
(the aim is to include a css depending on the parameter 'iconsize').
I am using the call:
get_function_bar_begin('iconsize' => '32');
for the subroutine get_function_bar_begin:
use strict;
...
sub get_function_bar_begin
{
my $self = shift;
my %template_params = %{ shift || {} };
return $self->render_template('global/bars /tmpl_incl_function_bar_begin.html',%template_params);
}
Why does this yield the error message:
Error executing run mode 'start': undef error - Can't use string ("iconsize") as a HASH ref while "strict refs" in use at CheckBar.pm at line 334
Am i doing something wrong here?
Is there an other way to submit my data ('iconsize') as a hash?
(i am still new to Perl)
EDIT: Solution which worked for me. I didn't change the call, but my function:
sub get_function_bar_begin
{
my $self = shift;
my $paramref = shift;
my %params = (ref($paramref) eq 'HASH') ? %$paramref : ();
my $iconsize = $params{'iconsize'} || '';
return $self->render_template('global/bars/tmpl_incl_function_bar_begin.html',
{
'iconsize' => $iconsize,
}
);
}
You are using the hash-dereferencing operator ( %{ } ) on the first argument of your parameter list. But that argument is not a hash reference, it's just the string 'iconsize'. You can do what you want by one of two ways:
Pass an anonymous hash reference:
get_function_bar_begin( { 'iconsize' => '32' } );
Or continue to pass a normal list, as you are right now, and change your function accordingly:
sub get_function_bar_begin {
my $self = shift;
my %template_params = #_;
}
Notice in this version that we simply assign the argument list directly to the hash (after extracting $self). This works because a list of name => value pairs is just syntactic sugar for a normal list.
I prefer the second method, since there's no particularly good reason to construct an anonymous hashref and then dereference it right away.
There's also some good information on how this works in this post: Object-Oriented Perl constructor syntax.
You're violating strict refs by trying to use the string iconsize as a hash reference.
I think you just want:
my( $self, %template_params ) = #_;
The first argument will go into $self and the rest create the hash by taking pairs of items from the rest of #_.
Passing hash with parameters as list
You need to use #_ variable instead of shift. Like this:
my %template_params = #_; ## convert key => value pairs into hash
There is different between hashes and references to hash in perl. Then you pass 'iconsize' => '32' as parameter this means list to perl, which can be interpreited as hash.
Passing hash with parameters as hash reference
But when you try %{ shift || {} } perl expect second parameter to be a hash references. In this case you can fix it in following way:
get_function_bar_begin({ 'iconsize' => '32' }); ## make anonymous hash for params
The problem is this line:
get_function_bar_begin('iconsize' => '32');
This does not pass a hash reference, as you seem to think, but a hash, which appears as a list to the callee. So when you do %{ shift }, you're only shifting the key 'iconsize', not the entire list. The solution is actually to make the second line of your function simpler:
my %template_params = #_;