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

Code speaks louder than words, so:
#!/usr/bin/perl -l use IO::Scalar; my $x = ""; { local *STDERR; tie *STDERR, 'IO::Scalar', \$x; print STDERR "foo"; untie *STDERR } print STDERR "bar"; print "caught: $x"; __END__ bar caught: foo
But if I drop the untie:
#!/usr/bin/perl -l use IO::Scalar; my $x = ""; { local *STDERR; tie *STDERR, 'IO::Scalar', \$x; print STDERR "foo"; } print STDERR "bar"; print "caught: $x"; __END__ caught: foobar
(I also find it odd that printing to a tieed filehandle doesn't honor the output record separator ($\)... but I don't care that much).

So question one: what the heck? Do tie and local just not play well together?

And question two: is there a way to do this? (I'd think that my intent here is pretty obvious.) I've tried several variants on the above, and I know that I can just change it so that it evals everything in the local scope (so that I can manually untie afterwards without worrying that an exception broke out of that block and left me no oppportunity to untie). But still I'm curious.

Thanks

------------ :Wq Not an editor command: Wq

Replies are listed 'Best First'.
Re: Tieing a local filehandle
by BrowserUk (Patriarch) on Aug 09, 2004 at 18:05 UTC

    If your on 5.8.1 (from memory), you can skip using IO::Scalar completely and using teh new form of open to a scalar (which means $/ is honoured correctly).

    #! perl -slw use strict; my $x; { local *STDERR; open STDERR, '>', \$x or die "STDERR $!"; print STDERR 'stuff'; warn 'Sommats up!'; } print STDERR 'More stuff'; print "Caught: $x"; __END__ P:\test>381308 More stuff Caught: stuff Sommats up! at P:\test\381308.pl line 9.

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
      Yes, that is cool, and I did know about that. I should have mentioned that I'm on 5.005_03.

      Thanks, though.

      ------------ :Wq Not an editor command: Wq
Re: Tieing a local filehandle
by ysth (Canon) on Aug 09, 2004 at 18:37 UTC
    Tied filehandles were revised in 5.8.0 specifically to address this problem. Ironically, this broke IO::Scalar->new (it no longer have DESTROY called when freed). This was fixed in 5.8.1.
Re: Tieing a local filehandle
by blokhead (Monsignor) on Aug 09, 2004 at 18:23 UTC
    Your two examples produce the same output for me (v5.8.4 i386-linux-thread-multi). You might want to search perldeltas for word of this fix/change (I didn't find anything clearly pointing to it in RFC: perlfeaturedelta, but it looks like local+tie interaction has been scrutinized throughout the 5.8 sequence). It's a bummer for you, since this change and the new open usage in BrowserUk's suggestion both were added after your perl version. I wonder if it's possible to subclass IO::Scalar and somehow get the object to untie itself upon DESTROY...

    The output record separator thing seemed weird to me at first too. But I got to thinking that for tied filehandles, READLINE has to manually deal with $/. Perhaps its for consistency that PRINT should deal with $\ manually as well. Also for some applications of tied filehandles (when they are not really performing a normal "filehandlish" function), having $\ automatically appended might not make any sense. In this case, I'd email the IO::Scalar maintainer and ask for the output separator to be honored by PRINT.

    Update: Also a reason for not automatically handling $\ is that you can pass multiple args to print, which are sent over raw to the tied PRINT method. Perl wants you to be able to use these multiple args to do anything you like, not just join them on $, (like a normal print). How exactly to automatically tack on $\ when there are multiple args to print is a problem!

    blokhead