DEV Community

Bob Lied
Bob Lied

Posted on

Reverse, but not that way

I tripped over these two things again, so maybe writing it down will plant it in my head.

The thing about reverse

I want to reverse a string. So easy.

my $str = 'WTF';
my $backwards = reverse $str;
say $backwards;
Enter fullscreen mode Exit fullscreen mode

And of course it prints 'FTW'. But another time I want to log the reverse for debugging, so I say:

say reverse $str;
Enter fullscreen mode Exit fullscreen mode

And it prints 'WTF'. Well, WTF. What happened here? The say command applies list context to the arguments. reverse in list context assumes you are passing it a list, and instead of reversing a string, it reverses the order of the list. There's only one thing in the list, and so it yields that one string, but not backward. What needs to happen is to assert scalar context:

say scalar reverse $str;
Enter fullscreen mode Exit fullscreen mode

The thing about the .. range operator

I started changing my idiom for for loops to use the range operator instead of the C-style assignment. That is, I replace

for (my $i = $start ; $i <= $end ; $i++) { say $i }
Enter fullscreen mode Exit fullscreen mode

with

for my $i ( $start .. $end )  { say $i }
Enter fullscreen mode Exit fullscreen mode

And then one day, I need to count backward. I naively set $start=9 and $end=1 and expect it to give me a descending sequence. Instead, the for loop doesn't appear to do anything at all.

What's going on? This is bash confusion (or ksh or zsh). In the shell, the direction of a range can be inferred from its endpoints.

$ echo {1..9}
1 2 3 4 5 6 7 8 9
$ echo {9..1}
9 8 7 6 5 4 3 2 1
$ seq 1 3
1
2
3
$ seq 3 1
3
2
1
$
Enter fullscreen mode Exit fullscreen mode

But in Perl, the range operator only works for increasing ranges; an attempt to descend will give an empty list. The way to get a descending sequence is to fall back on reverse

for my $i (reverse 1 .. 9) { ... }
Enter fullscreen mode Exit fullscreen mode

Top comments (0)