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

Assume that I have

use constant BIRD=>'footchicken';
and I want to constract a hash reference where BIRD is a key. Obviously I can not do
{ BIRD => 'Valery' }
because barewords on the lefthand side of => get quoted. Possible solutions are
{ BIRD() => 'Valery' } { BIRD, 'Valery' }
both of which I don't like very much (for purely aesthetic reasons). It therefore occured to me that
{ +BIRD => 'Valery' }
does not only look nice (for me, that is), but should work. However, it does not. Printing it out with Data::Dumper, i.e.
use strict; use warnings; use Data::Dumper; use constant { BIRD => 'footchicken' }; print Dumper(+{ +BIRD => 'Valery' });
displays:
$VAR1 = { 'BIRD' => 'Valery' };
This puzzles me. Why do I see BIRD here? Monadic + binds stronger than => and this means that we have +BIRD on the left of =>. This is certainly not a bareword, so it should evaluate as an expression, yielding 'footchicken'. And even in the unlikely case Perl would regard it as bareword here, quoting the beast would be '+BIRD', not 'BIRD'.

-- 
Ronald Fischer <ynnor@mm.st>

Replies are listed 'Best First'.
Re: On quoting the lhs of '=>'
by parv (Parson) on Jul 09, 2008 at 11:39 UTC

    Instead of non-working '+' or offending '()', you could use '&' (only one character long and in the same place as '+' would have been if it worked).

    Note also in perldoc (perl 5.8.8) ...

    Unary "+" has no effect whatsoever, even on strings. It is useful syntactically for separating a function name from a parenthesized expression that would otherwise be interpreted as the complete list of function arguments. (See examples above under "Terms and List Operators (Leftward)".)

    How about using Readonly already?

    Later ... one more way to make a constant (sub) behave: $p = { (P) => 1 } where P is a constant (sub).

      Instead of non-working '+' or offending '()', you could use '&'

      That's evil, I love you ;-)

      Note that this has an interesting side effect that you'll never be able to observe:

      use constant foo => 'bar'; sub crack { print &foo, $/; } crack(1, 2, 3);

      constant creates a sub foo () { 'bar' }, that is a constant sub with empty prototype.

      Using the & in front bypasses the prototype check, and it passes all arguments of sub crack to sub foo.

      Now since foo is constant sub, you have no way of observing the difference - except for speed:

      use Benchmark qw(cmpthese); cmpthese(-1, { 'ampersand' => 'use constant foo => 2; my $x = 0; for (1..10000) { + $x += &foo } ', 'no_amp' => 'use constant foo => 2; my $x = 0; for (1..10000) { + $x += foo } ', }); __END__ Rate ampersand no_amp ampersand 570/s -- -39% no_amp 939/s 65% --

      You can see that number of passed arguments makes a difference with this small benchmark:

      cmpthese(-1, { 'ampersand' => ' use constant foo => 2; sub a { my $x = 0; for (1..10000) { $x += &foo } } a(%ENV, %ENV, %ENV) ', 'no_amp' => ' use constant foo => 2; sub a { my $x = 0; for (1..10000) { $x += foo } } a(%ENV, %ENV, %ENV) ', }); __END__ Rate ampersand no_amp ampersand 330/s -- -61% no_amp 849/s 157% --

      Passing a relatively large array to the sub increase the run time difference.

        Thanks moritz for pointing out the speed difference which I had never considered before (not that I use & for sub calls myself).

        If speed really matters, then only two solutions remain (at least known to me yet) for OP to invoke the sub (created by constant pragma) in presence of left argument quoting comma: P(), (P) (where P is some sub).

        Time passes ... cdarke adds other options for invoking a sub in presence of fat comma.

      Thank you for pointing out Readonly. I will certainly have a look at it, and using & is a good suggestion too. However, the quote from perldoc,

      Unary "+" has no effect whatsoever, even on strings.

      does IMHO not explain the observed behaviour. Note that the decision of whether or not the lhs of => is taken as expression, depends (according to the docs) on whether or not it is a bareword. This is a purely syntactical issue and does not take into account what an operator does. We have +BIRD to the left of =>, and this is certainly not a bareword.

      If your interpretation of the perldoc is correct, the compiler's reasoning would go along the following line: "Hmmmm, we have +BIRD. I have no idea what BIRD is (haven't decided yet), but no matter what it is, + won't change it anyway, so just throw it away. This leaves us now with BIRD=>...., so now to the left of => we have a bareword; OK, let's quote it".

      I feel that this would be a very strange approach to compiling. Kind of: Evaluating unary + very early (because it is trivial to evaluate), and keep the other operators for later (because their interpretation depends on the context).

      Update: I would like to add that an unary + does work when it comes to access the element of a hash. For example, $x->{+BIRD}substitutes the constant BIRD. If your interpretation of perldoc would be correct, this expression should be treated equivalent to $x->{BIRD}, but (and IMO correctly), only in the latter case is BIRD taken as the string BIRD.

      -- 
      Ronald Fischer <ynnor@mm.st>

        The way I read the perldoc quote posted by parv (but I'm no expert), the compiler says "Hmmmm, we have +BIRD. I have no idea what BIRD is (haven't decided yet), but no matter what it is, but there's this unary + in front of it. Lessee, that + isn't between a function and a list of arguments, so it must have no effect whatsoever. That leaves us with a bareword BIRD; I know what to do with that."


        #my sig used to say 'I humbly seek wisdom. '. Now it says:
        use strict;
        use warnings;
        I humbly seek wisdom.
Re: On quoting the lhs of '=>'
by cdarke (Prior) on Jul 09, 2008 at 12:37 UTC
    Following on from parv's theme of using &, other operators work as well, with varying degrees of uglyness:
    $ref = { BIRD.'' => 'Valery' }; $ref = { BIRD x 1 => 'Valery' }; $ref = { ::BIRD => 'Valery' };
    Although I have to say I rather like the last one myself (and BIRD x 1 is fun)
    update: BTW, :: does not appear to ignore the prototype.
    update 2: Corrected parv's id.
Re: On quoting the lhs of '=>' (()++)
by tye (Sage) on Jul 09, 2008 at 16:40 UTC

    I always write Perl constants as BIRD(). Perl constants are subs and trying to hide this fact from yourself really isn't doing you any good in the long run, IMHO.

    There are lots of other places where barewords lead to potential ambiguities so I've found that the practice of avoiding barewords even in some places where Perl won't even warn about them can prevent misunderstandings between me and perl.

    At work we have a coding standard that requires literal hash key strings to be quoted. That is, $hash{foo}= { bar => 'baz' }; must instead be written $hash{'foo'}= { 'bar' => 'baz' };. This is actually one place where I personally violate my own 'no barewords' general principle. I used to follow a similar (personal) coding practice until a while after Perl changed the rules such that "hash key 'context'" became unambiguous (all barewords are quoted now; earlier only some barewords were quoted).

    These days I'm comfortable using barewords in "hash key 'context'". But part of the reason that I am is that I never write just shift nor just CONSTANT_NAME (etc.) but instead shift @_ and CONSTANT_NAME() so I don't get burned by "hash key 'context'" now being unambiguous.

    - tye        

      Perl constants are subs and trying to hide this fact from yourself really isn't doing you any good in the long run, IMHO.

      They are inlined subs, AFIK - semantically, they are subs; and from the implementation viewpoint, they are not. But basically I can understand your argument.

      -- 
      Ronald Fischer <ynnor@mm.st>
Re: On quoting the lhs of '=>'
by perrin (Chancellor) on Jul 09, 2008 at 18:35 UTC
    You're spending a lot of time on something that just isn't worth it. The performance gain from the constant pragma is never going to tip the balance in a real world application, and the problem only gets worse when you need to use them in double-quoted strings. Use a normal variable:

    our $BIRD = 'Valery';
      The performance gain from the constant pragma is never going to tip the balance in a real world application
      One optimization alone is never going to tip the balance. but imagine how slow perl scripts would be if *everybody* thought like that.
      i use a constant to switch on and off debugging in one of my modules, and i compared it to a normal variable, and the difference was big enough for me to use a constant. and as i'm doing benchmarks quite regularly i think i can estimate that.
      i'm so tired of all the people saying "don't optimize prematurely" while i have to use several awfully slow tools at work. and slow forums like this one. yes, don't optimize too early, but do it at least at *some* point.
      i just don't see why using a constant would be bad at all. trading speed for maintainability is usually not worth it, but what's wrong with a constant. just learn what you have to do if you use it as a hash key and in strings, and that's it.
        There are optimizations and there are optimizations. This one isn't worth it, except in special cases. You may have a special case with your debugging example.

        The problem with constant is just what you said: maintainability. Over the years, I have seen so many people have problems with the constant module that I consider it a frequent source of bugs. Yes, if you learn all the details of using it in hashes and strings you can make it work, but people "constantly" stumble over it. It's just too error-prone.

        Honestly, I don't see the point. Are you trying to guard against accidental assignment? It doesn't seem worth the trouble to me.
Re: On quoting the lhs of '=>'
by chibiryuu (Beadle) on Jul 09, 2008 at 17:38 UTC
    My way of preventing the fat arrow's quoting is
    use strict; use warnings; use Data::Dumper; use constant { BIRD => 'footchicken' }; print Dumper(+{ (BIRD) => 'Valery' }); # $VAR1 = { # 'footchicken' => 'Valery' # };
Re: On quoting the lhs of '=>'
by Anonymous Monk on Jul 09, 2008 at 15:53 UTC
    Your test code defines the constant BIRD differently from the code you initially ask about; perhaps that explains the difference in behavior?
      Your test code defines the constant BIRD differently from the code you initially ask about; perhaps that explains the difference in behavior?

      Thank you for pointing this out, but unfortunately it does not. The mistake was done when I edited the posting after having pasted the test code. Here is the original testcode - if you try it out, you will see that it shows the behaviour I was talking about in my post.

      use strict; use warnings; use Data::Dumper; use constant { BIRD => 'footchicken' }; print Dumper(+{ +BIRD => 'Valery' });
      In my original posting, I used "=" instead of "=>" in one place (I have this corrected now). This code, as posted here, wouldn't even have compiled.

      -- 
      Ronald Fischer <ynnor@mm.st>