Wednesday, November 18, 2009

pythonic perl 5: Use scalar

To illustrate this point, let's look at the different ways one can get the length of a list in Perl.

Let us say we have an array/list @mylist

  1. To get the length of @mylist, simply use @mylist in a scalar context. Remember that in Perl, there are 3 contexts: void, scalar and list. Using a list in a scalar context will return the length of the list.

  2. Sound easy? Well, yes and no. When reading through code in practice, it's quite painful to have to try to figure out whether something is being used in which context. And in fact, such errors will occur sooner or later. Which brings us to this technique. We use the scalar function to force the variable to be evaluated in a scalar context. And this I present to be the pythonic perl way to do it. The question you want to ask at this point is why bother typing extra characters if it's going to be evaluated in a scalar context anyway? There are a number of reasons. First it clarifies in the programmer's mind that this is exactly what you want to do. Secondly, it makes the code a LOT easier to read 6 months later when you have to go in and fix a bug.
  3. The third way has nothing to do whether to use scalar or not and uses the fact that the following is always true: scalar(@mylist) == $#mylist + 1 . My personal preference is to use scalar over this. Some people might prefer this. This is indeed a good alternative to using scalar and is preferable to the first method.

To summarize, the following will return the length of @mylist:

$len1 = @mylist;
$len2 = scalar( @mylist );
$len3 = $#mylist + 1;


szabgab said...

you almost never write $x = @data; or $x scalar @data;

The interesting case is this

if (@data) {
# array has elements

where it will be more readable without the scalar word once you get used to it.

rr said...

I believe that is only one use case for getting the length of a list. Sometimes you actually want to figure out the actualy length of the list. And you'd be doing something like this

if (@mylist ==
$someMagicScalarNumber) {

In this case I prefer to use scalar.

In the case you used, I do actually prefer to use:

if (@mylist) doSomething()

But then these are 2 different uses. And you are more likely to do this:

foreach my $item (@mylist) {