I'm confused by Perl Named Blocks (I thought they are...). Below is an example:
#!/usr/bin/perl
sub Run(&){
my ($decl) = #_;
$decl->();
}
sub cmd(&){
my($decl) = #_;
my(#params) = $decl->();
print "#params\n";
}
sub expect(&){
my ($decl) = #_;
my(#params) = $decl->();
print "#params\n";
}
Run {
cmd { "echo hello world " };
expect { exit_code => 0, capture => 2};
};
Note the last lines. It looks like "Run", "cmd", "expect" are named blocks, but not functions. Does anyone know what they are? Any available link introduces them?
I can't find any reference for such grammar.
Let's decipher this definition for Run:
sub Run(&){
my ($decl) = #_;
$decl->();
}
It means subroutine called Run, which accepts parameter of type CODE (that's why it uses (&)). Inside it $decl gets assigned to that passed code, and this code gets called by $decl->();.
Now, last lines in your example:
Run {
cmd { "echo hello world " };
expect { exit_code => 0, capture => 2};
};
are equivalent to:
Run(sub {
cmd { "echo hello world " };
expect { exit_code => 0, capture => 2};
});
In other words, it calls Run with anonymous procedure code that is in braces.
Run, cmd, and expect are prototype defined functions, and they work like built-in functions (no need to write sub{..}, as this is implicit due (&) signature for these functions).
If these functions were defined without prototypes,
sub Run { .. }
sub cmd { .. }
sub expect { .. }
then explicit sub{} arguments would be not optional but required,
Run(sub{
cmd(sub{ "echo hello world " });
expect(sub{ exit_code => 0, capture => 2});
});
They are subroutines accepting block as an argument. See: http://perldoc.perl.org/perlsub.html#Prototypes. The (&) in their definitions means that their first argument is a block of code.
Related
I want to write a function whose first parameter is a description, and the second parameter is a code block. I want the finished code to read like:
verify "description" { boolean-assertion-block };
I'm specifically looking to avoid the sub keyword.
I can put the description AFTER the code block, no problem:
sub verify (&$) { ... }
But when I reverse the prototype symbol order:
sub verify ($&) { ... }
Then I get an error message:
Type of arg 2 to main::verify must be sub {} (not anonymous hash ({})) at ...
Clearly, Perl has special handling for the first argument being a code block.
So, maybe I can make it a curried function?
sub verify ($) {
my $message = shift;
return sub (&) { . . . }
}
But then I get a syntax error between the description and the code block:
syntax error at ... near ""..." { "
I tried altering the calling syntax to try to help out the compiler:
test "...", { BLOCK };
test("..."){ BLOCK };
test("...")({ BLOCK });
( test "..." )({ BLOCK });
No joy. Can Perl even do what I want to do?
The (&) prototype only has such niceness when used for the first argument in a sub. From perldoc perlsub:
The interesting thing about "&" is that you can generate new syntax with it, provided it's in the initial position
One way to provide a similar level of niceness would be:
sub verify ($%) {
my ( $message, %opts ) = #_;
my $coderef = $opts{using};
...;
}
sub using (&) {
my ( $coderef ) = #_;
return ( using => $coderef );
}
# The `verify` sub accepts a name followed by a hash of options:
#
verify(
"your message here",
"using" => sub { ... },
);
# The `using` sub returns a two-element list that will satisfy
# that hash of options:
#
verify "your message here", using {
...;
};
If you desperately want to allow a syntax exactly like:
verify "description" { boolean-assertion-block };
... then it is still possible, but requires the dark arts. Keyword::Simple is probably your best bet, but Devel::Declare and Filter::Simple are options.
You can only use the block syntax if the & is the first thing in your prototype. From perlsub:
An & requires an anonymous subroutine, which, if passed as the first argument, does not require the sub keyword or a subsequent comma
Other custom DSL such as in Dancer2 or Mojolicious typically use the sub keyword.
get '/foo' => sub {
...
};
Plack::Builder and Web::Scraper use blocks that return objects, which then can be nested.
I just started work with a new team new place. They told me we return ref instead of value in our perl modules. Also I saw something like return +{foo=>'bar'}; and return {foo=>'bar'}; Whats the difference? And whether to return ref or value?
The + in return +{foo=>'bar'} is completely useless.
First, some background.
The Perl language has ambiguities. Take for example
sub f {
{ } # Is this a hash constructor or a block?
}
{ } is valid syntax for a block ("bare loop").
{ } is valid syntax for a hash constructor.
And both are allowed as a statement!
So Perl has to guess. Perl usually guesses correctly, but not always. You can give it "hints". Unary-+ can be used to do this. Unary-+ is a completely transparent operator; it does nothing at all. However, it must be followed by an expression (not a statement). { } has only one possible meaning as an expression.
+{ } # Must be a hash constructor.
Similarly, you can trick Perl to guess the other way.
{; } # Perl looks ahead, and sees that this must be a block.
Here's an example where Perl guesses wrong:
map { {} } 1..5 # ok. Creates 5 hashes and returns references to them.
map {}, 1..5 # XXX Perl guesses you were using "map BLOCK LIST".
map +{}, 1..5 # ok. Perl parses this as "map EXPR, LIST".
As for the code in the question, return must be followed by an expression (if anything), so there's only one possible interpretation for return { ... };, so the + is completely useless there.
Most people only disambiguate when necessary. Others might add + whenever it's ambiguous (even if Perl would guess right). But this is the first time I've heard of using + in front of every hash constructor.
Whats the difference?
Those are exactly the same, so the + is extraneous. You can see this by using B::Deparse:
$ perl -MO=Deparse -e'sub foo { return { foo => "bar" } }'
sub foo {
return {'foo', 'bar'};
}
-e syntax OK
$ perl -MO=Deparse -e'sub foo { return +{ foo => "bar" } }'
sub foo {
return {'foo', 'bar'};
}
-e syntax OK
In both cases, you're returning a reference to a hash.
As Hunter McMillen said in a comment, there are some cases where you need to use the unary + operator to resolve ambiguity.
For example, to distinguish between an anonymous hash and a block in a map:
$ perl -e'#a = map { $_ => "foo" }, 1..3' # { ... } treated as a block
syntax error at -e line 1, near "},"
Execution of -e aborted due to compilation errors.
$ perl -e'#a = map +{ $_ => "foo" }, 1..3' # { ... } treated as a hashref
And whether to return ref or value?
By "returning a value," I assume your coworkers mean something like this:
sub foo {
my %bar = ( baz => 'qux' );
return %bar; # as opposed to \%bar
}
my %hash = foo();
Subroutines can only return a list of scalars, so this is roughly equivalent to
my %hash = ('baz', 'qux');
If %bar contains many items, copying this list becomes expensive, so it can be better to return a reference instead:
sub foo {
my %bar = ( baz => 'qux' );
return \%bar;
}
my $hashref = foo();
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 don't know how to set default arguments for subroutines. Here is what I considered:
sub hello {
print #_ || "Hello world";
}
That works fine for if all you needed was one argument. How would you set default values for multiple arguments?
I was going to do this:
sub hello {
my $say = $_[0] || "Hello";
my $to = $_[1] || "World!";
print "$say $to";
}
But that's a lot of work... There must be an easier way; possibly a best practice?
I do it with named arguments like so:
sub hello {
my (%arg) = (
'foo' => 'default_foo',
'bar' => 'default_bar',
#_
);
}
I believe Params::Validate supports default values, but that's more trouble than I like to take.
I usually do something like:
sub hello {
my ($say,$to) = #_;
$say ||= "Hello";
$to ||= "World!";
print "$say $to\n";
}
Note that starting from perl 5.10, you can use the "//=" operator to test if the variable is defined, and not just non-zero. (Imagine the call hello("0","friend"), which using the above would yield "Hello friend", which might not be what you wanted. Using the //= operator it would yield "0 friend").
Also have a look at Method::Signatures. This uses Devel::Declare to provide some extra (needed!) sugar with the keywords method and func.
Below is your example using the new func:
use Method::Signatures;
func hello ($say='Hello', $to='World!') {
say "$say $to";
}
hello( 'Hello', 'you!' ); # => "Hello you!"
hello( 'Yo' ); # => "Yo World!"
hello(); # => "Hello World!"
/I3az/
If you see the documentation of Perl Best Practices: Default argument Values by Damian Conway then you will find some important points like:
Resolve any default argument values as soon as #_ is unpacked.
It suggest that if you have many default values to set up then the cleanest way would be factoring out the defaults into tables ie., a hash and then preinitializing the argument hash with that table.
Example:
#!/usr/bin/perl
use strict;
use warning;
my %myhash = (say => "Hello", to => "Stack Overflow");
sub hello {
my ($say, $to) = #_;
$say = $say ? $say : $myhash{say};
$to = $to ? $to : $myhash{to};
print "$say $to\n";
}
hello('Perl'); # output :Perl Stack Overflow
hello('','SO'); # output :Hello SO
hello('Perl','SO'); # output :Perl SO
hello(); # output :Hello Stack Overflow
For more detail and complete example refer Perl Best Practices.
Because Perl's mechanism for passing arguments to subroutines is a single list, arguments are positional. This makes it hard to provide default values. Some built-ins (e.g. substr) handle this by ordering arguments according to how likely they are to be used -- less frequently used arguments appear at the end and have useful defaults.
A cleaner way to do this is by using named arguments. Perl doesn't support named arguments per se, but you can emulate them with hashes:
use 5.010; # for //
sub hello {
my %arg = #_;
my $say = delete $arg{say} // 'Hello';
my $to = delete $arg{to} // 'World!';
print "$say $to\n";
}
hello(say => 'Hi', to => 'everyone'); # Hi everyone
hello(say => 'Hi'); # Hi world!
hello(to => 'neighbor Bob'); # Hello neighbor Bob
hello(); # Hello world!
Note: The defined-or operator // was added in Perl v5.10. It's more robust than using a logical or (||) as it won't default on the logically false values '' and 0.
I like this way the most: Since Perl 5.10 you can use // to check if a variable is defined or not and provide an alternative value in case it is not.
So, an easy example is:
my $DEFAULT_VALUE = 42;
sub f {
my ($p1, $p2) = #_;
$p1 //= 'DEFAULT';
$p2 // = $DEFAULT_VALUE;
}
Another option is using the shift instruction to get the params from #_:
sub f {
my $p1 = shift // 'DEFAULT';
}
Source: https://perlmaven.com/how-to-set-default-values-in-perl
There's the Attribute::Default module on CPAN. Probably cleaner than this, and avoids a couple of complexities (such as, what if you want to pass false to your subroutine?).
I've also seen people use my $var = exists #_[0] ? shift : "Default_Value";, but Perl's documentation notes that calling exists on arrays is deprecated, so I wouldn't really recommend it.
Snippet of Attribute::Default from the doc page:
sub vitals : Default({age => 14, sex => 'male'}) {
my %vitals = #_;
print "I'm $vitals{'sex'}, $vitals{'age'} years old, and am from $vitals{'location'}\n";
}
# Prints "I'm male, 14 years old, and am from Schenectady"
vitals(location => 'Schenectady');
The best way to address your problem have been discussed in the other answers.
One thing that strikes me though is that you state that:
sub hello {
print #_ || "Hello world";
}
And that works fine for if all you needed was one argument.
Have you actually tried that code? It will print the number of arguments or, when none provided, Hello World!
The reason for this is that the ||-operator takes precedence and forces the left-hand side in scalar context, thus reducing #_ to the number of arguments you provide, NOT the arguments itself!
have a look at perlop for more information on operators in Perl.
HTH,
Paul
For more sugar, see also Method::Signatures:
func add($this = 23, $that = 42) {
return $this + $that;
}
Imagine this subroutine:
sub test(&&)
{
my $cr1 = shift;
my $cr2 = shift;
$cr1->();
$cr2->();
}
I know I can call it like: test(\&sub1,\&sub2), but how can I call it like:
test { print 1 },{ print 2 };
If I say that the subroutine takes only one &, than sending a block will work. I don't know how to make it work with 2.
If I try to run it like that, I get:
Not enough arguments for main::test at script.pl line 38, near "},"
EDIT: is there no way of invoking without sub?
You need to explicitly say
test( sub { print 1 }, sub { print 2 } );
or
test { print 1 } sub { print 2 };
The implicit "sub" is only available for the first argument. http://perldoc.perl.org/perlsub.html#Prototypes:
An & requires an anonymous subroutine, which, if passed as the first argument, does not require the sub keyword or a subsequent comma.
Some things use an extra word in there to fake it:
test { print 1 } against { print 2 };
sub against (&) { $_[0] }
sub test (&#) { ... }
but I've never liked that much.
You can do this:
test(sub { print 1 }, sub { print 2 });
I've got the following code in one of my programs:
sub generate($$$$)
{
my ($paramRef, $waypointCodeRef, $headerRef,
$debugCodeRef) = #_;
...
&$headerRef();
...
my $used = &$waypointCodeRef(\%record);
And I call it with
CreateDB::generate(\%param, \&wayPointCode, \&doHeader, \&debugCode);
If you really want to bend the syntax more then take look at Devel::Declare
Examples of modules that use Devel::Declare:
MooseX::Declare (GitHub repo)
Test::Class::Sugar (GitHub repo)
PerlX::MethodCallWithBlock (GitHub repo)
Full list of modules on CPAN dependant on Devel::Declare can be found via CPANTS
Here is example from Test::Class::Sugar pod:
use Test::Class::Sugar;
testclass exercises Person {
# Test::Most has been magically included
startup >> 1 {
use_ok $test->subject;
}
test autonaming {
is ref($test), 'Test::Person';
}
test the naming of parts {
is $test->current_method, 'test_the_naming_of_parts';
}
test multiple assertions >> 2 {
is ref($test), 'Test::Person';
is $test->current_method, 'test_multiple_assertions';
}
}
Test::Class->runtests;
And here is something sexy from PerlX::MethodCallWithBlock pod:
use PerlX::MethodCallWithBlock;
Foo->bar(1, 2, 3) {
say "and a block";
};
Devel::Declare is a much more robust and saner way of contorting your Perl code compared to using a source filter like Filter::Simple.
Here is a video from its author which may help a bit more.
/I3az/