Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should I modify the prototype to allow construction of a hash after the coderef?

This is what I have:

use 5.14.0;
use strict;
use warnings;

sub my_func(&$) {
    my $coderef = shift;
    my %attribs = @_;
}

This is what I'd like to achieve:

my_func {
    print 1;
} first_attrib => "1",second_attrib => "2";

However, I receive the error Too many arguments for main::my_func at x.pl line 12, near ""2";". How should I modify the prototype, so that the parameters after the coderef will be transformed into a hash?

like image 713
Geo Avatar asked Dec 16 '11 13:12

Geo


2 Answers

If you change sub my_func(&$) to sub my_func(&%) your code will work.

The problem is that first_attrib => "1",second_attrib => "2" isn't a hash ref, but a list. And as friedo pointed out a list can be assigned to a hash, though a list with an odd number of elements might produce unwanted results and will produce a warning with use warnings.

Alternatively you can change your code to

sub my_func(&$) {
    my $coderef = shift;
    my ($attribs) = @_;
}

my_func {
    print 1;
} {first_attrib => "1",second_attrib => "2"};

to achieve what you seem to want.

The reason why you must wrap $attribs in parens is that assigning an array to a scalar returns just the number of elements in the array. At this point @_ is this array:

({first_attrib => "1",second_attrib => "2"})

with a hash ref as a single element.

($attribs) = @_;

tells perl to create an anonymous array with the scalar $attribs as its first element, and assign elements from @_ to the anonymous array, element by element, thus making $attribs point at the hash ref in @_.

like image 159
flesk Avatar answered Nov 15 '22 19:11

flesk


You need to realize the arguments to a Perl sub form a list. You use the first element of the argument list for the coderef and the remaining elements to form a hash:

#!/usr/bin/env perl

use 5.14.0;
use strict;
use warnings;

sub my_func(&@) {
    my $coderef = shift;
    my %attribs = @_;
    $coderef->() for keys %attribs;
}

my_func {
    print 1;
} first_attrib => "1",second_attrib => "2";
like image 24
Sinan Ünür Avatar answered Nov 15 '22 20:11

Sinan Ünür