Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Re^2: Filehandle in subroutine in use VRML.pm

by smittypaddler (Acolyte)
on Jul 07, 2022 at 12:43 UTC ( [id://11145325]=note: print w/replies, xml ) Need Help??


in reply to Re: Filehandle in subroutine in use VRML.pm
in thread Filehandle in subroutine in use VRML.pm

In the past my vrml scripts have always generated one set of VRML statements written to STDOUT on a given run, but in this latest script I wanted to create two wrl files in DrillPressTable.pl:

my $LumberFile="$Dir/$Subdir/lumber.wrl"; my $DrillPressTableFile="$Dir/$Subdir/$Subdir.wrl"; &mystart($LumberFile,LF); &buildlumber(\%Fs,LF,$Ppi); &mystart($DrillPressTableFile,DP); &buildtable(\%Fs,DP,$Ppi);

The original printout subroutine in VRML.pm looked like this, which I couldn't now use in DrillPressTableFile.pl because it had no provision for directing output to a filehandle other that STDOUT:

<code> sub printout { my($lines)=@_; foreach my $line (@{$lines}) { print "$line\n"; } } # End printout; </code)

The suggestion by Mr. Marshall didn't work, because the problem occurs when $fh at entry to printout is defined. Setting $fh to STDOUT is to have a default, and perhaps that would've been a problem if I'd gotten past the original problem of passing a filehandle to printout.

The myprint subroutine was to be only temporary until I figured out how to change printout to accept a filehandle, which brings me to my original question: How do I declare $fh in subroutine printout so it recognizes the intended filehandle?

Replies are listed 'Best First'.
Re^3: Filehandle in subroutine in use VRML.pm
by haukex (Archbishop) on Jul 07, 2022 at 20:10 UTC
    which brings me to my original question: How do I declare $fh in subroutine printout so it recognizes the intended filehandle?

    The problem is not in sub printout, it's here:

    &mystart($LumberFile,LF); &buildlumber(\%Fs,LF,$Ppi);

    This gives us a little more context as to what's going on. You apparently want to use the "filehandles" LF and DP like variables and pass them as arguments to the subs to use. But because of the missing strict, the LF is being taken as a bareword, that is, even though it looks like a filehandle, it's actually the string "LF" (B::Deparse on the sample code from the root node shows this). Then AFAICT this is being used as a symbolic reference by open and print, and this resolves it relative to the current package. When everything is in the main package, it works, but sub printout is in a different package, so it fails.

    Here's one possible solution that requires only very small changes to your code and even works under strict once you get around to using that. The do block basically generates a new filehandle (see also my node here for alternatives). This will actually give you a filehandle stored in a variable that you can pass around.

    my $LF = \do { local *LF; *LF }; &mystart($LumberFile,$LF); &buildlumber(\%Fs,$LF,$Ppi);

    I do still feel compelled to say that this is still just triage, though. The real issue is the missing strict compliance.

Re^3: Filehandle in subroutine in use VRML.pm
by Marshall (Canon) on Jul 11, 2022 at 20:58 UTC
    Hi smittypaddler,

    Again, you should use all strictures. use strict 'vars'; limits strict checking. use strict; is what you want.

    The code change that I gave you for printout() is correct. printout()won't work without that change. Past that, the problem is how you call printout().

    You cannot pass a simple bareword file handle like STDOUT as a parameter. Bareword filehandles are global in scope and don't need to be passed as parameters because they are known everywhere, in all subroutines. If you want to pass filehandles as a parameter, you should use lexically scoped filehandles (using "my") which can be passed as parameters. Also as a style rule, whatever level of the program opens a file, that level should be responsible for closing it.
    In your case, I would move the opening of the Lumber File up to the main program level. There is no need to ever create the "bareword filehandle, LH". Start off by creating a lexical filehandle to begin with and you don't have to worry about "translating" bareword to normal variable.

    my $LumberFile="$Dir/$Subdir/lumber.wrl"; open my $Lumber_fh, '<', $LumberFile or warn "Ooops Cannot Open Lumbe +r File: $LumberFile !! \n Proceeding using STDOUT"; my $out_fh = *STDOUT unless (defined $Lumber_fh); ... As a style point, I add "_fh" ("filehandle") as a suffix to remind myself that this variable is a filehandle and not some integer or other thing. The "*" in front of STDOUT is critical! This allows the "translation" of the bareword filehandle STDOUT into the lexical program variable "my $out_fh". Without that, Perl figures that STDOUT is a string. Now you can pass $out_fh as a parameter to other subs or use it yourself, e.g. print $out_fh "something";
    printout() is not needed. A single line suffices and is more clear.
    print $out_fh "$_\n" for @lines;

    Update:
    The error processing above is rather crude and I don't recommend it. In general, if there is a directory path that is supposed to be the "output file" and you can't open it, you should "die" and await changes to that filename/permissions. Normally you would not keep going and "waste" what might potentially be a significant computation effort. I would treat a null string $LumberFile name and non-null string $LumberFile differently.

    You might find amusing: A long time ago, when I was working with IBM mainframes, we had a job that ran for 5 days straight. That did not alarm us. We expected that. The unexpected part came when program abended due to a simple JCL (Job Control Language) error before writing the result to a magnetic tape. We had about 16 tape drives on that machine and it would have been completely fine for the program to "open" one of the drives for 5 days and hang on to it. The coding error that involved acquiring a tape drive for output wasn't apparent until after 5 days of number crunching! We lost 5 days of computing, the cost of which was not insignificant. So, in general I would open the output file before I had calculated some result to output to it.

      So, in general I would open the output file before I had calculated some result to output to it.

      For me it's a dilemma. Either: the case you described or ending up with an empty file created on disk after each error in between, which I then try to delete after each of the numerous error/abort conditions. Not an ideal world. Of course there's Perl's END{} but not all languages provide this.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (6)
As of 2024-04-18 06:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found