tniles
tniles

Reputation: 327

Learning Perl, One-Liner behaves differently

UPDATE

As pointed out in the answer, this question really has to do with Scalar versus List Context in Perl.

## ## ##

I am learning perl via self-taught crash course (primarily with the Llama book and the web). In attempting some byte swap code, I have found a one liner I do not understand completely. A comment in the script explains what I think is happening in the one-liner.

#!/usr/bin/perl --
#
# Script to print byte-swapped hex values
#

use 5.010;
use warnings;
use strict;

# NOTE: I realize I could use a single variable 'data', but the x- y- z- prefixes may help in
# identification (for clarity) in the code for this SO question.
my $xData;
my $yData;
my $zData;

for ( my $ijk = 998; $ijk < 1001; $ijk++ )
{
  printf ( "\n%4d is hex " . (sprintf "0x%04X", $ijk) . "\n", $ijk );

  # with byte swap
  say "These numbers (bytes swapped) should match...";

  # do sprintf, match pattern and store to ($1)($2), now reverse them into ($2)($1). 
  # BindOp leaves $_ alone, match stuffs $_ & is then used as input for reverse, prints.
  say reverse ((sprintf "%04X", $ijk) =~ /(..)(..)/) ;        # from perlmonks' webpage

  $yData = (reverse ((sprintf "%04X", $ijk) =~ /(..)(..)/) );
  say $yData;                         # does NOT match

  $xData = sprintf "%04X", $ijk;
  $xData =~ s/(..)(..)/$2$1/ ;
  say $xData;                         # does match

  $_ = sprintf "%04X", $ijk;
  /(..)(..)/;
  $zData = $2 . $1 ;
  say $zData;                         # does match
}

exit 0;

OUTPUT:

998 is hex 0x03E6 These numbers (bytes swapped) should match... E603 6E30 E603 E603

999 is hex 0x03E7 These numbers (bytes swapped) should match... E703 7E30 E703 E703

1000 is hex 0x03E8 These numbers (bytes swapped) should match... E803 8E30 E803 E803

Why does the one liner work, and why doesn't the $yData perform the same way? I'm pretty sure I understand why $xData and $zData work, but I would expect $yData to be the closest equivalent non-one-liner. What is the closest equivalent non-one-liner and why? Where is the discrepancy?

Upvotes: 0

Views: 102

Answers (1)

zdim
zdim

Reputation: 66883

The reverse in your print (say) statement comes in the list context, while when assigned to $yData the context is scalar. This function (may) behave considerably differently based on the context.

From perldoc -f reverse

reverse LIST
In list context, returns a list value consisting of the elements of LIST in the opposite order. In scalar context, concatenates the elements of LIST and returns a string value with all characters in the opposite order.

In this case this produces different results.


When called in list context, it swaps the (two) input bytes, keeping each byte intact (represented by two hexadecimal digits matched in a group). When called in scalar context, it joins the input and returns a character string, running in the opposite order. Taken to represent a hex number this would have each byte changed.

Upvotes: 1

Related Questions