ig has asked for the wisdom of the Perl Monks concerning the following question:
Investigating a "used only once" warning I was seeing using Config::Std, which uses Class::Std, I have reduced my program to the following test case:
A main program:
#!/usr/bin/perl use MyClass; my $obj = MyClass->new();
And a module: MyClass.pm
package MyClass; use Class::Std; # As in Config::Std::Hash my $hash_ref = {}; bless $hash_ref, 'MyClass'; 1;
This test program causes the Class::Std::DESTROY sub to be called twice. The first time the "used only once" warning is issued for MyClass::DEMOLISH but the second time it isn't. I don't understand why the warning is issued in the one case and not the other, as the code of the sub is the same in both cases. Can anyone explain?
Output of the test program is as follows:
Name "MyClass::DEMOLISH" used only once: possible typo at /usr/share/p +erl5/Class/Std.pm line 523.
For reference, the Class::Std::DESTROY sub is as follows:
sub DESTROY { my ($self) = @_; my $id = ID($self); push @_, $id; DEMOLISH: for my $base_class (_hierarchy_of(ref $_[0])) { no strict 'refs'; if (my $demolish_ref = *{$base_class.'::DEMOLISH'}{CODE}) { &{$demolish_ref}; } for my $attr_ref ( @{$attribute{$base_class}} ) { delete $attr_ref->{ref}{$id}; } } }
If I add a DEMOLISH sub in MyClass, as follows:
package MyClass; use Class::Std; my $hash_ref = {}; bless $hash_ref, 'MyClass'; sub DEMOLISH { print "demolishing...\n"; } 1;
then the warning is not issued. Again, I don't understand why as Class::Std::DESTROY remains the same. Within that sub, and the package and module that contain it, the symbol is still used only once.
So, I have a sub (Class::Std::DESTROY) which appears to reference the symbol MyClass::DEMOLISH only once, yet it sometimes does and sometimes does not issue the warning.
Note that if the bless $hash_ref, 'MyClass'; is removed from MyClass, no warning is issued at all, although Class::Std::DESTROY is still called for object created in the main routine, so it is not simply that the warning is issued only once for the block of code.
This is perl 5.10.0 with Class::Std 0.0.9.
update: I have reduced my test cases to the following:
#!/usr/bin/perl use warnings; sub foo { my $name = shift; if(my $ref = *{$name}{CODE}) { print "ref = $ref\n"; } } BEGIN { foo('bar'); }
produces:
Name "main::bar" used only once: possible typo at ./test2.pl line 6.
while...
#!/usr/bin/perl use warnings; sub foo { my $name = shift; if(my $ref = *{$name}{CODE}) { print "ref = $ref\n"; } } foo('bar');
produces nothing (i.e. no warning, no output at all)
The 'once' in 'used only once' encompasses all the executions of the sub during the compile phase. For example, the following:
#!/usr/bin/perl use warnings; sub foo { my $name = shift; if(my $ref = *{$name}{CODE}) { print "ref = $ref\n"; } } BEGIN { foo('bar'); foo('bar'); }
produces no warning.
But the following:
#!/usr/bin/perl use warnings; sub foo { my $name = shift; if(my $ref = *{$name}{CODE}) { print "ref = $ref\n"; } } BEGIN { foo('bar'); foo('baz'); }
produces two warnings:
Name "main::bar" used only once: possible typo at ./test2.pl line 6. Name "main::baz" used only once: possible typo at ./test2.pl line 6.
The 'used only once' warning is produce at the end of the compile phase for every variable in the symbol table for which the MULTI flag is not set, if the 'once' warning is enabled at that time and for the scope in which the variable appears.
I'm not certain when the MULTI flag is set, but I assume that when a symbol is used and not found in the symbol table, it is added with the MULTI flag not set, and when one is used and found in the symbol table the MULTI flag is set.
The execution of the sub during the compile phase can cause new symbols to appear in the symbol table without the MULTI flag set. If there is no other reference to these symbols during compilation, then the warning appears.
This is considerable progress from my complete confusion when I started investigating, but there are further puzzles to ponder: the warnings are lexically scoped (perllexwarn), but the symbols referenced are not necessarily lexically scoped variables. What then of a global symbol that is referenced only twice: once in a scope with the 'once' warning enabled and the other with it disabled? I'll test this, of course, and other variations and maybe, some day, be able to predict the effect of lexically scoped warnings on global variables.
update: It appears that whether a symbol is used once or not is independent of whether warnings are enabled or not. For example:
#!/usr/local/bin/perl # { use warnings; $foo = 1; $bar = 1; } { no warnings; $foo = 1; $baz = 1; }
produces only one warning:
Name "main::bar" used only once: possible typo at ./test3.pl line 7.
When a new symbol is added to a symbol table, the MULTI flag is set on unless warnings are on either globally or lexically in the scope that caused the symbol to be added. Otherwise, the MULTI flag is set on if a symbol is referenced and found in the symbol table. The 'used only once' warning is issued if the MULTI flag is still off at the end of the compile.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: "used only once" warning from Class::Std
by ikegami (Patriarch) on Apr 25, 2010 at 04:16 UTC | |
by ig (Vicar) on Apr 25, 2010 at 05:29 UTC | |
|
Re: "used only once" warning from Class::Std
by Khen1950fx (Canon) on Apr 25, 2010 at 02:36 UTC | |
by ig (Vicar) on Apr 25, 2010 at 03:04 UTC | |
by Anonymous Monk on Apr 25, 2010 at 03:21 UTC | |
by ig (Vicar) on Apr 25, 2010 at 04:52 UTC |