Perl dereferencing in non-strict mode

156 Views Asked by At

In Perl, if I have:

no strict;
@ARY = (58, 90);

To operate on an element of the array, say it, the 2nd one, I would write (possibly as part of a larger expression):

$ARY[1]  # The most common way found in Perldoc's idioms.

Though, for some reason these also work:

@ARY[1]
@{ARY[1]}

Resulting all in the same object:

print (\$ARY[1]);
print (\@ARY[1]);
print (\@{ARY[1]});

Output:

SCALAR(0x9dbcdc)
SCALAR(0x9dbcdc)
SCALAR(0x9dbcdc)

What is the syntax rules that enable this sort of constructs? How far could one devise reliable program code with each of these constructs, or with a mix of all of them either? How interchangeable are these expressions? (always speaking in a non-strict context).

On a concern of justifying how I come into this question, I agree "use strict" as a better practice, still I'm interested at some knowledge on build-up non-strict expressions.

In an attemp to find myself some help to this uneasiness, I came to:

  • The notion on "no strict;" of not complaining about undeclared variables and quirk syntax.
  • The prefix dereference having higher precedence than subindex [] (perldsc § "Caveat on precedence").
  • The clarification on when to use @ instead of $ (perldata § "Slices").
  • The lack of "[]" (array subscript / slice) description among the Perl's operators (perlop), which lead me to think it is not an operator... (yet it has to be something else. But, what?).

For what I learned, none of these hints, put together, make me better understand my issue.

Thanks in advance.

4

There are 4 best solutions below

0
On BEST ANSWER

Quotation from perlfaq4:

What is the difference between $array[1] and @array[1]?

The difference is the sigil, that special character in front of the array name. The $ sigil means "exactly one item", while the @ sigil means "zero or more items". The $ gets you a single scalar, while the @ gets you a list.

Please see: What is the difference between $array[1] and @array[1]?

0
On

@ARY[1] is indeed a slice, in fact a slice of only one member. The difference is it creates a list context:

@ar1[0] = qw( a b c );    # List context.
$ar2[0] = qw( a b c );    # Scalar context, the last value is returned.
print "<@ar1> <@ar2>\n";

Output:

<a> <c>

Besides using strict, turn warnings on, too. You'll get the following warning:

Scalar value @ar1[0] better written as $ar1[0]

In perlop, you can read that "Perl's prefix dereferencing operators are typed: $, @, %, and &." The standard syntax is SIGIL { ... }, but in the simple cases, the curly braces can be omitted.

See Can you use string as a HASH ref while "strict refs" in use? for some fun with no strict refs and its emulation under strict.

2
On

Extending choroba's answer, to check a particular context, you can use wantarray

sub context { return wantarray ? "LIST" : "SCALAR" }

print $ary1[0] = context(), "\n";
print @ary1[0] = context(), "\n";

Outputs:

SCALAR
LIST
0
On

Nothing you did requires no strict; other than to hide your error of doing

@ARY = (58, 90);

when you should have done

my @ARY = (58, 90);

The following returns a single element of the array. Since EXPR is to return a single index, it is evaluated in scalar context.

$array[EXPR]

e.g.

my @array = qw( a b c d );
my $index = 2;
my $ele = $array[$index];   # my $ele = 'c';

The following returns the elements identified by LIST. Since LIST is to return 0 or more elements, it must be evaluated in list context.

@array[LIST]

e.g.

my @array = qw( a b c d );
my @indexes ( 1, 2 );
my @slice = $array[@indexes];   # my @slice = qw( b c );

\( $ARY[$index]   )  # Returns a ref to the element returned by $ARY[$index]
\( @ARY[@indexes] )  # Returns refs to each element returned by @ARY[@indexes]

${foo}       # Weird way of writing $foo. Useful in literals, e.g. "${foo}bar"
@{foo}       # Weird way of writing @foo. Useful in literals, e.g. "@{foo}bar"
${foo}[...]  # Weird way of writing $foo[...].

Most people don't even know you can use these outside of string literals.