1

I have decided to learn Perl as my next language and I am currently reading about the scalar and list contexts, although this question is not specifically Perl-related, I will just put it in a Perl context (hah, get it?!)

So, the basic idea is that operators expect either a scalar or a list value, and if they get an argument that is of a different type than the one they are expecting, they will convert it to the appropriate context.

A couple of examples of the correct contexts being used:

# Scalar context
$first_number = 2;
$second_number = 3;
say 3+2; # This obviously prints 5

# List context
@array = qw (one two three);
@array = reverse @array;
say @array; # Prints threetwoone

Now, if you mix contexts, you can get something like this:

$first_number = 2;
@array = qw (one two three);
$result = 2 + @array;
say $result; # This prints 5

This is because using an array in a mathematical operation returns the length of the array instead.

Now, the question is: why would you ever want to do this unless you are an evil person and you want to make people reading your code miserable? Would it be too mainstream to use something like 2 + $#array instead?

In general, is it good programming practice to let the language take care of this type of scenario? Wouldn't it be better if the programmer took care of the variables and prepared data so that all operators received the correct argument type in the first place?

2 Answers2

4

Larry designed Perl to DWIM (Do What I Mean). If you're using an array in scalar context, meaning that you are using the array in a context where there is exactly one value that represents it, that one value you most likely want is its length. Thus, when you do that, that's what you get. If the situation were different, perhaps the single value that most people would want most of the time was the index of the last inserted element (which might be somewhere in the middle), an array in scalar context would do that.

$#array, which is the index of the last element, is wrong if you want the length. It's one less than that. It's also not the most common single value you'd want to know about an array because Perl handles list extending for you. You don't need to know the last element to add another element. You don't even need to know the last element to get it since Perl can count backward: $array[-1] is always the last element. This bit of knowledge is much less likely to be the single value you'd want in scalar context.

A better illustration of this philosophy are the getpw* functions, such as getpwnam. In list context, it returns a list of the elements for the user entry from the password table for the named user. In scalar context, it returns the one value of that list that you probably want if you only want one value. That's the UID of the named user. There's no rule that governs what a particular thing will do in scalar context other than giving you the value that most people probably want.

This is Perl handling some of the mundane details for you so you can get on with the task instead of fiddling with moving things around. If you're coming from a simpler language and are used to having to do much more work to do common things, this might seem odd. After spending some time with Perl, you might come to appreciate how much Perl does for you so you don't have to do the boring stuff.

Note that you had the tag "type-conversion", but that's not what's going on here. Perl isn't casting or coercing anything. An array is always an array. The variables and values can respond to context, but that doesn't change what they are. It's not using the same bit pattern to mean something different like you can do in C, for instance.

brian d foy
  • 1,962
  • Sorry, I actually meant $#array+1 there, I was writing in a hurry. And ok for the type-conversion tag, it was the closest tag I could find :P Your answer makes sense, but doesn't this whole idea of "let's give you what you probably want" make everything more difficult to read, albeit faster to write, especially if you come from other languages where you have to make more stuff explicit? Up to the reader I suppose, but still... – user1301428 Aug 06 '15 at 09:51
  • Sure, you meant that, but that's not what you actually did, which is the same thing as what many people actually do when they introduced such a bug. – brian d foy Aug 06 '15 at 10:13
  • Well, I suppose if that's the philosophy of the language everything makes sense I guess. – user1301428 Aug 06 '15 at 11:07
1

$#array is (well, historically was - this variable has been deprecated in 5.12.0) impacted by the value of the $[ (see also $ARRAY_BASE in the perldoc perlvar documentation) and can cause the straightforward use of $#array + 1 to give invalid or unexpected results.

In some cases identifying what context a sub call has been made in (void, scalar, or array) can allow the sub to optimize the work it needs to do (if this optimization should be done or not is left as an argument for the code review).

For example, an iterator might be able to reset itself in the case of void context ($iterator->()), return the next item in scalar context (my $item = $iterator->()), or return the remaining items in array context (my @items = $iterator->()).

I have glossed over some parts of what bdf stated above so as not to duplicate his fine explanation.