Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

understanding this syntax

by Anonymous Monk
on Oct 01, 2010 at 15:43 UTC ( [id://862976]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hello monks, could you please help me understand this syntax? Why do we have parentheses around FOO/BAR in the hash? Thanks a bunch!

use constant FOO => 10; use constant BAR => 20; %BAZ = ( FOO() => 1, BAR() => 1 ); sub is_baz { my $i = shift; return ( exists $BAZ{$i} ) ? 1 : 0; } .... is_baz(10);

Replies are listed 'Best First'.
Re: understanding this syntax
by kennethk (Abbot) on Oct 01, 2010 at 15:51 UTC
    Your issue comes from using the => operator. From the documentation,

    The => operator is a synonym for the comma except that it causes its left operand to be interpreted as a string if it begins with a letter or underscore and is composed only of letters, digits and underscores. This includes operands that might otherwise be interpreted as operators, constants, single number v-strings or function calls. If in doubt about this behaviour, the left operand can be quoted explicitly.

    The arrow is stringifying your argument, and the parens prevent that behavior. You would also get your expected behavior by swapping to explicit commas:

    use constant FOO => 10; use constant BAR => 20; %BAZ = ( FOO, 1, BAR, 1 ); sub is_baz { my $i = shift; return ( exists $BAZ{$i} ) ? 1 : 0; } .... is_baz(10);
Re: understanding this syntax
by ikegami (Patriarch) on Oct 01, 2010 at 16:10 UTC

    Without the parens, you'd get %BAZ = ('FOO', 1, 'BAR', 1); due to the autoquoting behaviour of =>. The author wanted %BAZ = (10, 1, 20, 1);. Each of the following achieve the desired results:

    %BAZ = ( FOO, 1, BAR, 1 ); %BAZ = ( (FOO) => 1, (BAR) => 1 ); %BAZ = ( FOO() => 1, BAR() => 1 );

    The last requires knowing that constants can be called like functions. I prefer the middle version. Actually, no. I'd use the following since it eliminates redundancies and illustrates the intent better:

    %BAZ = map { $_ => 1 } FOO, BAR;

    By the way,

    sub is_baz { my $i = shift; return ( exists $BAZ{$i} ) ? 1 : 0; }

    can be simplified to

    sub is_baz { my $i = shift; return $BAZ{$i}; }
      Thanks for the great explanation tpo both of you guys!!!
Re: understanding this syntax
by molecules (Monk) on Oct 01, 2010 at 17:31 UTC

    I don't know if the question was edited, but at this moment the question says "Why do we have parentheses around FOO/BAR in the hash?".

    Hash assignment takes a list. The following shows that a lack of parentheses makes a difference:

    use strict; use warnings; use constant FOO => 10; use constant BAR => 20; use Data::Dump qw/ dump /; my %BAZ = ( FOO() => 1, BAR() => 1 ); my %BOO = ( FOO => 1, BAR => 1 ); my %BAH = FOO => 1, BAR => 1; print 'BAZ: ' . dump(\%BAZ) . "\n"; print 'BOO: ' . dump(\%BOO) . "\n"; print 'BAH: ' . dump(\%BAH) . "\n";

    This prints:

    Useless use of a constant (BAR) in void context at temp/hash_test.pl line 17.
    Odd number of elements in hash assignment at temp/hash_test.pl line 17.
    BAZ: { 10 => 1, 20 => 1 }
    BOO: { BAR => 1, FOO => 1 }
    BAH: { FOO => undef }
    
    

    Both comma operators (i.e. " =>" and " ,") have lower precedence than the assignment operator " =". Thus the assignment operator takes only the first argument to its right, which for the hash %BAH is the value for the constant FOO. It doesn't even "see" anything to the right of the first fat comma  => or even the comma itself.

    Using parentheses around everything to the right of the assignment operator creates a list that the assignment operator in turn uses to create the hash.

    Perl is an "Operator-oriented language" as chromatic mentions in his blog post Perl and the Least Surprised.

Re: understanding this syntax
by TomDLux (Vicar) on Oct 02, 2010 at 05:09 UTC

    Part of your question, though you didn't realize is, is how use constant works.

    use constant creates a subroutine of no arguments for the constant you want, which returns the desired value. You COULD do the same manually.

    sub FOO(?) {10;} sub BAR(?) {20;}

    While it does work in expressions, FOO is not recognized as being a subroutine, when you use it in a string. While there are ways to make it be interpolated within a real string, which may or may not work in the fat-arrow string, the more modern solution is to use Readonly instead of <c.constant</c>. Readonly gives you real scalars, arrays, hashes which can't be modified.

    use Readonly Readonly my $FOO => 10; Readonly my @GAMES => ( 'tennis', 'crocket', 'crazy eights' ); Readonly my %NUMBERS => ( consonents => [ qw( b c d f g h j k l m n p q r s t v w x z) +], vowels => [ qw( a e i o u y ) ], );

    As Occam said: Entia non sunt multiplicanda praeter necessitatem.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://862976]
Approved by kennethk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (4)
As of 2024-03-29 11:30 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found