The syntax is an unusual way of encapsulating the modification of several values at once inside of one statement.
This code is probably used at the end of a subroutine, as it returns a list of values. The real code might look like this.
sub foo {
my @a = qw(Sun Mon Tue Wed Thu Fri Sat);
my @b = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
my $s = q{foobar};
# wday month mday hour min sec year
return sub { ( $a[ $_[6] ], $b[ $_[4] ], $_[3], $_[2], $_[1], $_[0], $_[5] + 1900 ) }
->(localtime), $s;
}
Let's go through that. I added the return to make it more clear what's happening.
There is an anonymous subroutine sub { ... }, which is defined and directly being called sub { ... }->(). This is like a lambda function. The arrow operator -> in this form is used for calling a code reference. It differs from the direct object syntax (e.g. $foo->frobnicate()) in that there is no method name after the arrow.
my $code = sub { print "@_" };
$code->(1, 2, 3);
This will output:
1, 2, 3
The localtime return value in list context is passed. That's a bunch of values for the current time, as mentioned in the documentation.
# 0 1 2 3 4 5 6 7 8
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
localtime(time);
Without arguments, localtime implicitly uses time as its argument. Inside of the anonymous subroutine, those values end up in @_, which is the argument list of the sub. So $_[0] is the seconds part of the current local date.
Then there is @a and @b, which are really badly chosen names. If it's supposed to be short, I'd at least have called them @d and @m for weekdays and months.
The anonymous sub returns a list of values. It's the current weekday, as looked up in the @a array, where Sunday is index 0, the current month as looked in @b, the day, hour, minute and second, and the year as a four-digit number (hence the + 1900).
The overall function foo returns this list, and another value $s as the last element of its return value list.
If you were to print all of that, you would get:
print join q{ }, foo();
__END__
Mon Sep 25 16 10 33 2017 foobar
In the context of the sprintf, this becomes more clear. It's likely for adding a timestamp to a log entry.
sub log {
my $s = shift;
my @a = qw(Sun Mon Tue Wed Thu Fri Sat);
my @b = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
# 0 1 2 3 4 5 6 7
$s = sprintf "%s %s %d %d:%d:%d %d: %s",
# wday month mday hour min sec year
# 0 1 2 3 4 5 6
sub { ( $a[ $_[6] ], $b[ $_[4] ], $_[3], $_[2], $_[1], $_[0], $_[5] + 1900 ) }
# 7
->(localtime), $s;
return $s;
}
print &log('stuff happened'); # we need the & because CORE::log
I've marked each value with the position of the argument inside the sprintf pattern. $s seems to be the log message, which is replaced by the new string with the timestamp, and itself as the last argument.
However, this is a very unusual implementation, given that localtime will return the exact same thing in scalar context.
print &log("stuff happened\n");
print ''.localtime . ": stuff happened\n";
__END__
Mon Sep 25 16:24:40 2017: stuff happened
Mon Sep 25 16:24:40 2017: stuff happened
It's the return value of ctime(3). I first thought maybe it's a reimplementation because on the target system that kind of timestamp does not exist, but the localtime docs also say that this is not system-dependent.
The format of this scalar value is not locale-dependent but built into
Perl. For GMT instead of local time use the gmtime builtin. See also
the Time::Local module (for converting seconds, minutes, hours, and
such back to the integer value returned by time), and the POSIX
module's strftime and mktime functions.
The implementation with the sub is elegant, though not very Perl-ish. However, it's completely useless because Perl already brings this exact same format.
You could easily replace my log function with this.
sub log {
my $s = shift;
$s = localtime . " $s";
return $s;
}
But then again, if @a and @b are maybe localized, this makes makes sense. You give them as letter, which is probably not your real code, but I could see this being used as for example translating it to German like this.
use utf8;
sub log {
my $s = shift;
my @a = qw(So Mo Di Mi Do Fr Sa);
my @b = qw(Jan Feb Mär Apr Mai Jun Jul Aug Sep Okt Nov Dez);
# 0 1 2 3 4 5 6 7
$s = sprintf "%s %s %d %d:%d:%d %d: %s",
# wday month mday hour min sec year
# 0 1 2 3 4 5 6
sub { ( $a[ $_[6] ], $b[ $_[4] ], $_[3], $_[2], $_[1], $_[0], $_[5] + 1900 ) }
# 7
->(localtime), $s;
return $s;
}
print &log("stuff happened\n");
Now it makes a lot more sense.
@aand@band$swould help. I can tell you what it's doing, but not why. Also, how is this used? On its own the return value is lost. Is this assigned to something, or is it the return value of another function?