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

I'm developing a module which, among other things: opens, selects, and keeps track of output file handles. A user can call: openOut(*OUT,$outputFile) and the handle is auto-selected so that prints without file handles go to the opened output file. There's also a corresponding closeOut(*OUT), but I don't want to force the user to call it. Hence, when I use the module, I will see:
Runtime warning: [Name "main::OUT" used only once: possible typo at no +close_test.pl line 50.].
I was reading up on this warning and saw that somehow the sort builtin manages to suppress these warnings regarding $a and $b. That's what I'd like to do, but for whatever file handle the user decides to use in the call to my openOut method. Can I do that from my module without forcing the user to add any extra code?

I know I can catch these warnings with a SIG{__WARN__}, but I don't want to suppress good warnings or add detail to an unrelated warning about suggesting a call to closeOut.
  • Comment on How to suppress "only used once" regarding script file handles (that are in fact used in my module), but do it from a the module?
  • Select or Download Code

Replies are listed 'Best First'.
Re: How to suppress "only used once" regarding script file handles (that are in fact used in my module), but do it from a the module?
by Corion (Patriarch) on Nov 07, 2019 at 16:52 UTC

    The traditional approach is to just use the filehandle twice:

    sub openOut { select *main::OUT = *main::OUT; # squelch "used once" warning ...

    Alternatively, you can disable the warning, see warnings:

    sub openOut { { no warnings 'once'; select *main::OUT; } ...

    The best approach IMO would be to do away with the global filehandle names alltogether and pass in the filehandle from the main program. but I guess that's beyond the scope of your question :)

      Hmmm...

      Perhaps I described the problem inadequately. The user of my module creates the file handle. My module exports openOut and it takes a file handle as its first argument in a variable:

      sub openOut { my $file_handle = $_[0]; my $output_file = $_[1]; ... }
      I use that file handle (in variable form - stored in a hash actually) multiple times throughout the module. My module doesn't know the bareword handle name, so I can't directly reference *main::OUT in my module code to "use it twice". Even if I get the name of the bareword file handle with some trick like $bareword_filehandle = select(), I wouldn't guess that I could satisfy the "use it more than once" requirement regarding main without typing the thing out in the code, and if I did that inside the module, I don't know if that would work for the warning about the file handle in main. How does sort do it WRT $a and $b? And how wouyld I replicate that when I don't know the name of the handle?

      So... if I put no warnings 'once' inside my openOut sub in my module, are you saying that that would suppress warnings about *OUT (or whatever hard-coded handle the user creates) in main?

      Here's a full example of a user's script who would be using my module (we'll call it Foo for now):

      #!perl use Foo qw(openOut); openOut(*BAR,"~/output.txt"); print("Hello world!\n");

      I do have a feature planned to possibly make the openOut method return an anonymous file handle. That would solve the problem, but it would create other problems, which I haven't worked out yet.

        Forgoing a lexical (you’re calling it “anonymous”) filehandle gives you some serious problems you may not have considered. Best practice is never GLOBAL handles (excepting built-ins…).

        I agree with all three replies you've received to this so far. I would also add (my anonymous brother's comment notwithstanding) that you can avoid this problem entirely simply by returning the opened filehandle rather than accepting it as an argument. eg. In your module:

        sub openOut { my $filename = shift; open my $fh, '>', $filename or die $!; select $fh; return $fh; };

        In this way, the user of your module can either call this sub in void context if they don't care about closing the handle later (this avoiding the "once" warning) or in scalar context if they do. eg:

        # void context, no handle to close openOut ("file1"); print "foo\n"; # scalar context, handle stored so can be closed, printed to explicitl +y, etc. my $handle = openOut ("file2"); print "bar\n"; closeOut ($handle);

        I think you're over-thinking this. If the warning is coming from their script and not from your module, it's their job to eliminate the warning. In their script they can do no warnings 'once';, or they can use the name twice.

        Now, you could do something like this in your module:

        sub import { warnings->unimport('once'); }

        … which will effectively do no warnings 'once' on their behalf, but unimporting warnings for your caller is only something you should be doing if you document it in big red letters in your documentation.

        "How does sort do it WRT $a and $b?"

        Perl special cases the $a and $b package variables, not requiring them to be declared with our, and not warning about them being used only once. They're magic. Not as magic as other built-in variables, but still a little magic.

        Here's a full example of a user's script who would be using my module (we'll call it Foo for now):

        Hi

        Thats a tad , optimistic? ;)

        use Path::Tiny qw/ path /; select my $bar = path("~/output.txt")->opena_utf8; print "Hello world!\n";

        At least thats this user's opinion

        Modern Perl , the future is now :)

        $ perl - use Path::Tiny qw/ path /; select path("~/output.txt")->opena_utf8; print "Hello world!\n"; __END__ $ cat %home%\output.txt Hello world! $ del %home%\output.txt $