Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Re: Filehandle in subroutine in use VRML.pm

by bliako (Monsignor)
on Jul 08, 2022 at 09:19 UTC ( [id://11145353]=note: print w/replies, xml ) Need Help??


in reply to Filehandle in subroutine in use VRML.pm

I understand that you want to pass filehandles to functions with the added feature that if user specified an undefined handle, said function and the rest of the program should use default STDOUT.

Firstly, try and migrate from bareword filehandles to lexical ones, except when you use the standard ones: STDERR, STDIN, STDOUT. So avoid using open FH, '>', 'xyz'; in favour of my $fh; open $fh, '>', 'xyz';

printout() below accepts a reference to a variable containing the filehandle. If contents of ref are not defined then it sets them to STDOUT and then proceeds in printing to the filehandle by dereferencing the ref (using {$$fhref} the curlies are used for disambiguating the syntax). Setting the fhref to STDOUT affects the caller since it is a reference to a variable of the caller.

my $fh = undef; print "1.fh is now $fh\n"; printout("some lines", \$fh); print "2.fh is now $fh\n"; printout("some lines", \$fh); print "3.fh is now $fh\n"; $fh = undef; # <<<< very important, else redirects STDOUT to xxx open $fh, '>', 'xxx'; printout("some lines", \$fh); print "4.fh is now $fh\n"; close $fh; sub printout { my ($lines, $fhref) = @_; $$fhref = *STDOUT unless $$fhref; print {$$fhref} $lines; }

There is some serious potential bug with above code. In open $fh, '>', 'xxx';, if $fh is set to STDOUT (and not undef as is the usual use-case) then it redirects STDOUT to 'xxx'! This and because I prefer that the one who opens the filehandle to close it as well, I would not use this idea of printout() setting the filehanlde to STDOUT which can then be inherited to all subsequent calls by the caller. I find it an unecessary complication. But printout() printing to STDOUT if no filehandle was given, is fine logic to me. So:

my $fh = undef; printout('some lines1', $fh); open $fh, '>', 'xxx'; printout('some lines2', $fh); close $fh; sub printout { my ($lines, $_fh) = @_; my $fh = $_fh ? $_fh : *STDOUT; print $fh $lines; }

bw, bliako

Replies are listed 'Best First'.
Re^2: Filehandle in subroutine in use VRML.pm
by smittypaddler (Acolyte) on Jul 09, 2022 at 00:15 UTC

    If I've understood Mr Bliako's message correctly, it doesn't work. The open in DrillPressTable.pl and the call to printout are the same, and the error message begins "print() on unopened filehandle LF...", and printout is changed according to his message:

    sub printout { my ($lines, $_fh) = @_; my $fh = $_fh ? $_fh : *STDOUT; foreach my $line (@{$lines}) { print $fh "$line\n"; } } # End printout;

      ... despite my various solutions and workarounds from my nodes here and here being much better than the following, if you're hell-bent on only modifying sub printout, here's enough rope to shoot yourself in the foot: (Update: Note the following only works because of the absence of strict...)

      sub printout { my ($lines, $_fh) = @_; my $fh = $_fh ? caller.'::'.$_fh : *STDOUT; foreach my $line (@{$lines}) { print $fh "$line\n"; } } # End printout;

      Though you may need to replace caller with the string "main" if printout gets called from another package. /shudder

        I disagree in one detail. I believe that you must specify the package which contains open $fh, ..., not the package which contains the call to printout. Of course in this case, they are the same (main::).
        Bill
      I understand that you want to pass filehandles to functions with the added feature that if user specified ...

      Alas it seems I did not understand exactly. In my code above I assume that you will open a file using open my $fh, ... and that you pass around that filehandle and not a literal string/bareword representing also a filehandle, which gets complicated, having to specify also package names. So, in the code I provided the part open $fh, '>', 'xxx'; is essential. The following works for me:

      { package main; my $fh = undef; VRML::printout('some lines1', $fh); open $fh, '>', 'xxx'; VRML::printout('some lines2', $fh); close $fh; } { package VRML; sub printout { my ($lines, $_fh) = @_; my $fh = $_fh ? $_fh : *STDOUT; print $fh $lines; } }

      bw, bliako

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (5)
As of 2024-04-19 06:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found