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

    I don't understand why the warning is issued in the one case and not the other,

    It's a compile-time warning. Unless you compile the code twice, it's not going to warn twice.

      It makes sense that it would be a compile time warning and be issued only once for a given compilation. I had thought this initially but then was confused when I instrumented Class::Std. I changed Class::Std::DESTROY to (note the addition of print statements, no other changes):

      sub DESTROY { my ($self) = @_; my $id = ID($self); push @_, $id; print "here we are in DESTROY\n"; DEMOLISH: for my $base_class (_hierarchy_of(ref $_[0])) { no strict 'refs'; print "destroying $base_class\n"; # no warnings 'once'; if (my $demolish_ref = *{$base_class.'::DEMOLISH'}{CODE}) { print "about to call destroy on $base_class\n"; &{$demolish_ref}; } for my $attr_ref ( @{$attribute{$base_class}} ) { delete $attr_ref->{ref}{$id}; } } }

      Running my program against this modified version of Class::Std produces this:

      here we are in DESTROY destroying MyClass Name "MyClass::DEMOLISH" used only once: possible typo at Class/Std.pm + line 528. here we are in DESTROY destroying MyClass

      I suppose this comes down to an issue of which compile time. Since we are dealing with a symbolic reference, the value of which isn't known until runtime, the compilation, if there is such a thing for a symbolic reference, must be deferred until what is to be compiled is know.

      To further test the idea that a compile time warning would be issued only once, I added another object to the module, as follows:

      package MyClass; use strict; use warnings; use Class::Std; my $hash_ref = {}; bless $hash_ref, 'MyClass'; my $hash_ref2 = {}; bless $hash_ref2, 'MyClass'; 1;

      And was surprised to see the following output - without any warning:

      here we are in DESTROY destroying MyClass here we are in DESTROY destroying MyClass here we are in DESTROY destroying MyClass

      The subroutine that only references the symbol once, but is called three times no longer causes a warning to be produced. Yet in the initial case, where it was called twice, it does cause a warning to be produced. I am now more puzzled than before. I suspect I have a fundamental misunderstanding of the scope over which use warnings qw(once); operates and what happens at compile time(s) Vs what happens at runtime. This would be nothing new.

      And there is yet another issue. If i remove the blessing of the hash reference to MyClass:

      package MyClass; use strict; use warnings; use Class::Std; my $hash_ref = {}; #bless $hash_ref, 'MyClass'; 1;

      And run this against my modified version of Class::Std, I get the following output:

      here we are in DESTROY destroying MyClass

      Here we have the same subroutine passed the same base class, producing the same symbolic reference, yet no warning is produced.

      So, it seems not to be a simple as a compile time warning being produced only once for one bit of code.

      My (potentially mis-)understanding is that the sub DESTROY is defined and compiled once, when the Class::Std module is compiled. A reference to the sub is then added to the symbol table of MyClass, and it is executed one, two or three times, depending on which version of the test is run.

      It is the bless $hash_ref, 'MyClass'; in MyClass that stimulates the warning, but only if it occurs only once - if it occurs twice, there is no warning. And calling DESTROY on the object created by the new method of MyClass, exported from Class::Std, does not cause a warning to be issued.

Re: "used only once" warning from Class::Std
by Khen1950fx (Canon) on Apr 25, 2010 at 02:36 UTC

      Thanks for that. It looks like good guidance for future changes/implementations. None the less, I would like to understand why perl is behaving the way that it is.

      BTW, it occurs to me that a reference to sub DESTROY is being added to the namespace of the package that uses Class::Std. Thus, in my test case, the sub isn't being invoked as Class::Std::DESTROY, but rather as MyClass::DESTROY. But it's the same code and I don't see how that would make any difference to whether the warning is issued or not.