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.
| [reply] [d/l] |
|
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
| [reply] |
|
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. ;)
| [reply] [d/l] |
|
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.
| [reply] [d/l] |
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.
| [reply] [d/l] [select] |
|
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;}
| [reply] [d/l] |
Re: Constant redefined
by thcsoft (Monk) on May 31, 2005 at 11:28 UTC
|
| [reply] |
|
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...
| [reply] |
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.
| [reply] [d/l] |
|
use warnings;
use constant foo => 10;
BEGIN {
no warnings;
undef &foo;
*foo = sub () {20}
}
| [reply] [d/l] |
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...
| [reply] [d/l] |
|
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.
| [reply] [d/l] |
|
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?
| [reply] |