Reverse an array, a string or a number
Given an array of values my @words = qw(Foo Bar Moo);, how can we reverse the order of the values to get Moo Bar Foo?
Given a string my $str = 'stressed';, how can I get the characters in reverse order to get 'desserts'?
Given a number: 3.14, how can I reverse it to get 41.3?
As Perl does not care much if the content of a scalar variable is a string or a number, reversing a string or a number is the same. So we only have two cases: reversing a scalar and reversing an array.
The function reverse can be used in both cases:
use strict; use warnings; use 5.010; my @words = qw(Foo Bar Moo); say join ' ', @words; my @sdrow = reverse @words; say join ' ', @sdrow;
And the output is:
Foo Bar Moo Moo Bar Foo
Reverse a scalar: string or number
use strict; use warnings; use 5.010; my $str = 'stressed'; say $str; my $rev = reverse $str; say $rev; my $n = 3.14; say $n; my $u = reverse $n; say $u;
And the output is:
stressed desserts 3.14 41.3
So the same function can be used for two similar things. This is nice, but it also has some pitfalls.
The two behaviors of reverse are not decided by its parameter, but by the construct that is on the left hand side.
If you try to reverse an array but put the assignment in SCALAR context, the result might surprise you:
my $str = reverse @words; say $str;
The same if you try to reverse a string, but put the assignment in LIST context:
my $str = 'stressed'; my @words = reverse $str; say $words;
Of course, it is not very likely that you'll write code like in the latest example, but what about these examples:
my $str = 'stressed'; say reverse $str;
Looks strange. As if reverse had no impact.
What about this one?
my @words = qw(Foo Bar Moo); say reverse join '', @words;
That might be surprising. Did the reverse not work there, or were the words already reversed? What if we do the same, but without the call to reverse:
my @words = qw(Foo Bar Moo); say join '', @words;
That would be baffling. As if reverse has not impact. Indeed, if you try to reverse a string (the result of join in this case), but put the call in LIST context created by the say function, then it tries to reverse the list given to it string-by-string. Like in this case:
my $str = 'stressed'; my ($rev) = reverse ($str); say $rev;
In order to fix the above issues, we need to make sure reverse is called in SCALAR context which can be achieved using the scalar function:
my $str = 'stressed'; say scalar reverse $str; my @words = qw(Foo Bar Moo); say scalar reverse join '', @words;
(Thanks to Jonathan Cast reminding me to add these examples.)
Remember, the behavior of reverse depends on its context. On what is on its left-hand side.
Published on 2014-04-11