Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl: Can't pass an "on-the-fly" array to a sub

Tags:

arrays

perl

strftime(), as per cpan.org:

print strftime($template, @lt);

I just can't figure the right Perl code recipe for this one. It keeps reporting an error where I call strftime():

...
use Date::Format;
...
sub parse_date {
 if ($_[0]) {
  $_[0] =~ /(\d{4})/;
  my $y = $1;
  $_[0] =~ s/\d{4}//;
  $_[0] =~ /(\d\d)\D(\d\d)/;
  return [$2,$1,$y];
  }
 return [7,7,2010];
 }

foreach my $groupnode ($groupnodes->get_nodelist) {
    my $groupname = $xp->find('name/text()', $groupnode);
    my $entrynodes = $xp->find('entry', $groupnode);
    for my $entrynode ($entrynodes->get_nodelist) {
        ...
        my $date_added = parse_date($xp->find('date_added/text()', $entrynode));
        ...
        $groups{$groupname}{$entryname} = {...,'date_added'=>$date_added,...};
        ...
        }
    }
...

my $imday = $maxmonth <= 12 ? 0 : 1;
...

while (my ($groupname, $entries) = each %groups) {
    ...
    while (my ($entryname, $details) = each %$entries) {
        ...
        my $d = @{$details->{'date_added'}};
        $writer->dataElement("creation", strftime($date_template, (0,0,12,@$d[0^$imday],@$d[1^$imday]-1,@$d[2],0,0,0)));
        }
    ...
    }
...

If I use () to pass the required array by strftime(), I get: Type of arg 2 to Date::Format::strftime must be array (not list) at ./blah.pl line 87, near "))"

If I use [] to pass the required array, I get: Type of arg 2 to Date::Format::strftime must be array (not anonymous list ([])) at ./blah.pl line 87, near "])"

How can I pass an array on the fly to a sub in Perl? This can easily be done with PHP, Python, JS, etc. But I just can't figure it with Perl.

EDIT: I reduced the code to these few lines, and I still got the exact same problem:

#!/usr/bin/perl

use warnings;
use strict;
use Date::Format;

my @d = [7,13,2010];
my $imday = 1;
print strftime( q"%Y-%m-%dT12:00:00", (0,0,12,$d[0^$imday],$d[1^$imday]-1,$d[2],0,0,0));
like image 473
R. Hill Avatar asked Jul 19 '10 15:07

R. Hill


People also ask

What does @_ mean in Perl?

Using the Parameter Array (@_) Perl lets you pass any number of parameters to a function. The function decides which parameters to use and in what order.

How do I determine the size of an array in Perl?

Note: In Perl arrays, the size of an array is always equal to (maximum_index + 1) i.e. And you can find the maximum index of array by using $#array. So @array and scalar @array is always used to find the size of an array.

What is array in Perl?

An array is a variable that stores an ordered list of scalar values. Array variables are preceded by an "at" (@) sign. To refer to a single element of an array, you will use the dollar sign ($) with the variable name followed by the index of the element in square brackets.


2 Answers

Where an array is required and you have an ad hoc list, you need to actually create an array. It doesn't need to be a separate variable, you can do just:

strftime(
    $date_template,
    @{ [0,0,12,$d[0^$imday],$d[1^$imday],$d[2],0,0,0] }
);

I have no clue why Date::Format would subject you to this hideousness and not just expect multiple scalar parameters; seems senseless (and contrary to how other modules implement strftime). Graham Barr usually designs better interfaces than this. Maybe it dates from when prototypes still seemed like a cool idea for general purposes.

like image 130
ysth Avatar answered Sep 30 '22 13:09

ysth


To use a list as an anonymous array for, say, string interpolation, you could write

print "@{[1, 2, 3]}\n";

to get

1 2 3

The same technique provides a workaround to Date::Format::strftime's funky prototype:

print strftime(q"%Y-%m-%dT12:00:00",
               @{[0,0,12,$d[0^$imday],$d[1^$imday]-1,$d[2],0,0,0]});

Output:

1900-24709920-00T12:00:00
like image 35
Greg Bacon Avatar answered Sep 30 '22 13:09

Greg Bacon