-5

I'm Perl beginner.I did not get why we use context(scalar,list,void) in perl.

Please clarify my doubt with simple example.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
  • Provide some context to your question, use where? – Noam Rathaus Dec 16 '13 at 06:39
  • @nrathaus i already mentioned in question as `beginner`.I don't about `Context`.give simple example in perl language – user3098497 Dec 16 '13 at 06:44
  • 1
    This question could be closed as off-topic for several reasons, including the lack of specificity mentioned by @nrathaus. I decided to answer because it is an absolutely essential and often misunderstood feature of Perl. It should be useful for beginners. – Palec Dec 16 '13 at 07:15

1 Answers1

3

Simple example with array

An array is a list of contained values in list context, while number of contained values in scalar context. In void context, its value is thrown away.

$, = ' '; # printed fields will be delimited by spaces
my @arr = qw/a b c d/;
@arr; # nothing done (thrown away) in void context
print @arr, "\n"; # function arguments are evaluated in list context by default
print scalar(@arr), "\n"; # scalar() forces scalar context

“By default” refers to subroutine prototypes. See perlsub manual page (man perlsub).

Output:

a b c d
4

Void context example and explanation

Void context is not really interesting IMO. It is throwing the value away. If you call a subroutine returning a value without capturing that value (e.g. in a variable), it is called in void context. Notice that implicit return looks like not capturing the value, but in that case the context is inherited from the caller.

sub x {
    return 42;
}
x(); # evaluated in void context

What one could view as interesting is that this generates no error, even though the subroutine returns something. Only when warnings are enabled, using constant or variable in void context generates warning.

Context inside subroutines

In a subroutine, caller’s context can be determined using wantarray. It returns undef for void context, true for list context and false for scalar context. The expression in return’s argument is evaluated in this context.

sub print_context {
    my $context = wantarray;
    unless (defined $context) {
        print "void\n";
    } elsif ($context) {
        print "list\n";
    } else {
        print "scalar\n";
    }
    return ''; # empty string
}
print_context(); # void
scalar(print_context()); # scalar
(print_context()); # void
print print_context(); # list
print (print_context()); # list
print +(print_context(), print_context()); # list twice
print scalar(print_context(), print_context()); # void, scalar (comma operator throws away its left operand’s value)
print scalar(+(print_context(), print_context())); # void, scalar (same as above)
print scalar(@{[print_context(), print_context()]}); # list twice, 2 once (array of two empty strings)

I must admit that scalar(print_context()); surprised me. I expected void.

More and more complicated artificial examples can be found.

Practical problems related to context

The need to be aware of what context is comes from several practical problems though:

  • determining array size by forcing scalar context (usually via scalar() or using one of the operators expecting scalars)
  • solving accidents when array is erroneously evaluated in scalar context (thus expanded to its size) and was not intended to by forcing list context
  • using operators and subroutines that behave differently in different contexts (e.g. =~, ,, <> a.k.a. readline, localtime, reverse, each, caller, …; and those user-defined using wantarray, naturally)

General and very deep truths about context

  • The concept of context is explained in perldata manual page (man perldata).
  • Left operand of assignment operator (=) determines the context for evaluation of the right one. Behavior of assignment operator depends on type of left operand.
  • Aforementioned subroutine prototypes incluence context of evaluation of their parameters. See perlsub manual page (man perlsub).
  • The expression in return’s argument is evaluated in the context inherited from caller.
  • Parentheses have nothing to do with context, not even with list context and lists generally. They’re always just changing precedence. Or they’re surrounding function call parameter list, forming a term. See perlop manual page (man perlop).
Community
  • 1
  • 1
Palec
  • 12,743
  • 8
  • 69
  • 138
  • I'm waiting for editing answer..please make it – user3098497 Dec 16 '13 at 06:53
  • i tried your answer `my @arr = qw/a b c d/; print @arr, "\n"; print scalar(@arr), "\n";` it giving output like `abcd 4`.why it showing without space in between letters? – user3098497 Dec 16 '13 at 07:00
  • @user3098497 Sorry, forgot to mention use of `$,` (output field separator). See `man perlvar`. Editing again. – Palec Dec 16 '13 at 07:06
  • using `join()` function we can reduce this one – user3098497 Dec 16 '13 at 07:06
  • @user3098497 After using join, the two lines will differ more than in the context in that `@arr` is evaluated. – Palec Dec 16 '13 at 07:10
  • @downvoter Care to comment why downvoted, how to improve? – Palec Dec 16 '13 at 09:27
  • Re "I must admit that `scalar(print_context());` surprised me. I expected void.", You explicitly instructed Perl to set the context to scalar, so it obliged. – ikegami Dec 16 '13 at 15:09
  • @ikegami That makes sense when looking at `scalar()` as something really special. I was used to the idea that what looks like a function really is a function. If `scalar()` was a function, the context would be void inside in this case. – Palec Dec 16 '13 at 15:43
  • @Palec, Not so. Arguments of functions are never called in void context. It would be list, or scalar given the right prototype. Remember, you're printing `print_context`'s context, not `scalar`'s. – ikegami Dec 16 '13 at 15:47
  • @ikegami You’re right. So scalar could be defined more-or-less as `sub scalar($) { return shift; }`… Interesting. – Palec Dec 16 '13 at 16:00
  • Yup! Though in practice, in results in no code at all. e.g. `diff -u <( perl -MO=Concise,-exec -E'say @a' 2>&1 ) <( perl -MO=Concise,-exec -E'say scalar(@a)' 2>&1 )`. Betcha can't guess what the `s` and `l` mean in that difference ;) – ikegami Dec 16 '13 at 16:27