perl-diddler has asked for the wisdom of the Perl Monks concerning the following question:

Why doesn't this work (yes, I can work around the problem with use Readonly, but that wouldn't tell me why Constant doesn't work).
#/usr/bin/perl -w use strict; use constant { Undefined => 0, Page => 1, Index => 2, }; my %map = ( Page => 'mypage', Index => 'myindex', ); foreach my $k (keys %map) { printf "key=%s, val=%s\n", $k, $map{$k}; }
Instead of the value of Page, '1', being used as a key, the string 'Page' is being used. If a literal value of page was being used to initialize %map, wouldn't I get a strict warning about using an unquoted string?

Replies are listed 'Best First'.
Re: why doesn't constant work?
by ikegami (Patriarch) on Nov 11, 2010 at 05:07 UTC
    As always, parens disabmiguate.
    my %map = ( (Page) => 'mypage', (Index) => 'myindex', );
Re: why doesn't constant work?
by roboticus (Chancellor) on Nov 11, 2010 at 04:19 UTC

    perl-diddler:

    In this case, the => operator treats the bare word to the left as a string literal.

    ...roboticus

      Is there anyway I can force it into being eval'ed for the value of constant? (or do I have to put it a variable...?)
        #/usr/bin/perl use strict; use warnings; use constant { Undefined => 0, Page => 1, Index => 2, }; {my %map = ( Page => 'mypage', Index => 'myindex', ); use Data::Dumper qw(Dumper); print Dumper \%map;} {my %map = ( Page() => 'mypage', Index() => 'myindex', ); print Dumper \%map;}

        And this is why Perl Best Practices says to use Readonly (with Readonly::XS installed, preferably) instead of constant.

        Well, one of the reasons anyway. Another is string interpolation. And I think there are more, though I can't remember them off the top of my head :-)

        perl-diddler:

        From the docs:

        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.

        So I'd suggest just using a comma:

        my %map = ( Page, 'mypage', Index, 'myindex', );

        Notes: (1) Untested, as I don't recall ever using the constant module before, and (2) Yes, it looks strange to me, too!

        ...roboticus

Re: why doesn't constant work?
by moritz (Cardinal) on Nov 11, 2010 at 07:18 UTC
Re: why doesn't constant work?
by BrowserUk (Patriarch) on Nov 11, 2010 at 04:22 UTC

    Swith the '=>' for ',' in your hash initialisation:

    my %map = ( Page, 'mypage', Index, 'myindex', );

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: why doesn't constant work?
by TomDLux (Vicar) on Nov 11, 2010 at 15:21 UTC

    People referred to it, but didn't explicitly state ... The way use constant works is it creates a subroutine which takes no arguments for your symbolic name, for example 'Page'. It's exactly the same as if you had:

    sub Page() { return 1; }

    That works as far as preventing the value of Page from being altered, but it doesn't interpolate anywhere, because interpolation happens with variables, not barewords. As already mentioned, that's why Readonly has become the preferred method:

    use Readonly; Readonly my $Page => 1;

    That will interpolate the value wherever needed.

    By the way, good style generally calls for ALL CAPS for global variables and constants. The reason is it stands out as a sin you've committed, motivating programmers to minimize the use to things that actually need it.

    As Occam said: Entia non sunt multiplicanda praeter necessitatem.