Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Constant redefined

by paulski (Beadle)
on May 31, 2005 at 02:48 UTC ( [id://461909]=perlquestion: print w/replies, xml ) Need Help??

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

The following test script produces an error:
#!/usr/bin/perl use constant TEST => 1; use constant TEST => 2; print("TEST: " . TEST . "\n");

Constant subroutine main::TEST redefined at /usr/lib/perl5/5.8.0/constant.pm line 108. TEST: 2

Now I know the reason for the error, but is there a way to suppress this particular error message? i.e. what if I had a valid reason for doing this?

Thanks,

Paul

Replies are listed 'Best First'.
Re: Constant redefined
by davido (Cardinal) on May 31, 2005 at 04:30 UTC

    The answer to this question is found in constant (the documentation for the constant pragma), where it states:

    In the current implementation, scalar constants are actually inlinable subroutines. As of version 5.004 of Perl, the appropriate scalar constant is inserted directly in place of some subroutine calls, thereby saving the overhead of a subroutine call. See "Constant Functions" in perlsub for details about how and when this happens.

    That statement means that constants are both declared at, and solidified at compiletime, and cannot be altered. You would literally have to go back and alter all the inlined values in the compiled code at runtime. Constants are...constant. ;)

    The fact that constants are translated into inline values instead of the subroutine calls that they "look" like means that even if you tried to assign a new subroutine to the typeglob by which the constant is named, you can't. The typeglob for the sub seems to be forever tied to that inlined value.

    Of course if you read on in the docs to the BUGS section you'll find the following:

    In the current version of Perl, list constants are not inlined and some symbols may be redefined without generating a warning.

    Exploiting that bug should not be for the faint of heart. In fact, exploiting it should just not ever be done, because its possible the behavior will go away if someone decides to fix that bug.


    Dave

      I'm aware of how constants work i.e. I did read the doco before I asked :-) and realise that PERL constants are just inline subs. I'm more interested in suppressing the error message, if possible.

      Thanks,

      Paul

        I'm sorry for misunderstanding the intent of your question. Ok, so despite the fact that it violates the intent of constants, you're looking for a way to suppress any error message anytime a constant is defined again with the "use constant..." directive. Here's some rope:

        use warnings; use strict; BEGIN{ open OLDERR, '>&', \*STDERR or die "Couldn't save STDERR\n$!"; close STDERR; } INIT{ open STDERR, '>&', \*OLDERR or die "Couldn't retrieve STDERR\n$!"; } use constant PI => 3.14; use constant PI => 1000; print PI, "\n";

        You are now suppressing any error messages that would occur during the stage of compilation where 'use' directives are being sorted out and compiled. That means there are a lot of other errors you won't see. In fact, I doubt you would even see any error caught by my 'or die...' clauses while saving away STDERR. I did give STDERR back to you for runtime stuff though. But this whole thing seems like a BAD IDEA.

        By the way, holli is wrong about being able to wrap it in an eval BLOCK. I tried that too. ;)


        Dave

        You can suppress this error as you can suppress every error. Put in an eval BLOCK. But then the constant will still have the old value.

        Oh yeah. Compile time. My bad.


        holli, /regexed monk/
Re: Constant redefined
by tlm (Prior) on May 31, 2005 at 02:58 UTC

    It's only a warning. You can suppress it with no warnings

    { no warnings; use constant TEST => 2; }

    Update: Dang. That no warnings bit was all wrong, as noted by K_M_McMahon++. The worst of it is that I had even run the test

    % perl -Mstrict -wle 'use constant x => 1; { no warnings; use constant + x => 4; } print x' Constant subroutine main::x redefined at /opt/lib/perl5/5.8.3/constant +.pm line 108. 4
    but only paid attention to the fact that the last print out was correct, and completely ignored the fact that I was still getting a warning. Sheesh.

    the lowliest monk

      I still get the error even using your no warnings code or with a global no warnings

      I am curious about the need to redefine a constant. If you are going to be changing its' value, you should be using variables anyway....

      -Kevin
      my $a='62696c6c77667269656e6440676d61696c2e636f6d'; while ($a=~m/(^.{2})/s) {print unpack('A',pack('H*',"$1"));$a=~s/^.{2}//s;}
Re: Constant redefined
by thcsoft (Monk) on May 31, 2005 at 11:28 UTC
    err... honestly: you are trying to assign two different values to the same constant. apart from that you might as well tell an orange to be green and yellow at exactly the same spot, i would be especially interested in the reasons you pretend to have for such a funny idea.

    it is not by accident, that there exists a difference between a constant and a variable. and neither is it arbitrary, that variables use to differ by their names.

    language is a virus from outer space.

      i would be especially interested in the reasons you pretend to have for such a funny idea.

      Not to answer for the OP, but I have a module that traverses namespaces wrapping all functions in a closure. This is equivalent to the problem above, though the intention is not to redefine constants.

      it is not by accident, that there exists a difference between a constant and a variable

      No, but it is an arbitrary implementation detail that constants would be functions that rely on folding in the parser.




      time was, I could move my arms like a bird and...
Re: Constant redefined
by salva (Canon) on May 31, 2005 at 11:35 UTC
    I have not been able to test it, but maybe this would work:
    use constant foo => 1; BEGIN { undef &foo } use constant foo => 2;

    update: well, it silences the original warning but causes a new one related to changed prototypes.

      this actually works:
      use warnings; use constant foo => 10; BEGIN { no warnings; undef &foo; *foo = sub () {20} }
Re: Constant redefined
by Ctrl-z (Friar) on May 31, 2005 at 12:05 UTC
    Ive done this using davidos closing STDERR approach. Depending on what you really are doing - assuming its not just defining a constant twice - you can minimise the loss of real warnings elsewhere, eg
    package Yuk; sub import { 1. close stderr 2. do that thing 3. reopen stderr }



    time was, I could move my arms like a bird and...

      I'm unhappy with the solution I provided above because it seems like a really "Bad Idea" to close STDERR right in the middle of compilation, even if it is only for a little while. Who knows what other messages that is causing to be squelched! And that can make debugging a nightmare.

      So I set out to find another more wholesome solution. It can't really be considered wholesome to tie a filehandle (tied filehandles aren't even yet fully reliable and fully implemented), but its better than sticking ones head in the sand like an ostrich by closing STDERR at such a critical moment.

      So that's exactly my solution; tie STDERR to a class that squelches only messages containing the word "constant". Here it is, and as you can see, it works great.

      use warnings; use strict; BEGIN{ package ConstErr; use Tie::Handle; our @ISA = qw(Tie::Handle); sub TIEHANDLE { bless \my $i, shift; } sub PRINT { my $r = shift; print grep { $_ !~ m/constant/i } @_; } package main; tie *STDERR, 'ConstErr'; } use constant PI => 3.14; print PI, "\n"; use constant PI => 1000; print PI, "\n";

      Again, let me reiterate that I still consider the whole idea to be a bad one, but if the purpose of this discussion is purely academic, and only seeking to find solutions to a theoretical problem, this is the best solution I can think of.


      Dave

        But isn't this conceptually incorrect? why would someone want to modify a constant? if it was to be modified then why is it declared as a constant in the first place?

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others exploiting the Monastery: (6)
As of 2024-04-24 06:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found