Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

open undef shift

by Anonymous Monk
on Oct 03, 2009 at 15:49 UTC ( [id://799021]=perlquestion: print w/replies, xml ) Need Help??

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

What is going on here
#!/usr/bin/perl -- use strict; use warnings; sub huh1 { my $huh = open my $fh, '>', $_[0] or die $!; $huh += print $fh 'huh1'; $huh += close $fh; } sub huh2 { my $huh = open my $fh, '>', shift or die $!; $huh += print $fh 'huh2'; $huh += close $fh; } sub huh3 { my $huh = open my $fh, '>', undef or die $!; $huh += print $fh 'huh3'; $huh += close $fh; } sub huh31 { my @yund; my $huh = open my $fh, '>', shift @yund or die $!; $huh += print $fh 'huh31'; $huh += close $fh; } sub huh4 { my $yund; my $huh = open my $fh, '>', $yund or die $!; $huh += print $fh 'huh4'; $huh += close $fh; } print huh1(),"\n"; print huh2(),"\n"; print huh3(),"\n"; print huh31(),"\n"; print huh4(),"\n"; __END__ 3 3 3 3 Use of uninitialized value $yund in open at - line 32. No such file or directory at - line 32.

Replies are listed 'Best First'.
Re: open undef shift
by almut (Canon) on Oct 03, 2009 at 16:22 UTC

    No explanation (yet), just an observation: strace shows Perl is creating temp files in all but the last case where the file name slot is $yund:

    ... open("/tmp/PerlIO_Ol6dlF", O_RDWR|O_CREAT|O_EXCL, 0600) = 3 unlink("/tmp/PerlIO_Ol6dlF") = 0 open("/tmp/PerlIO_WFvCgM", O_RDWR|O_CREAT|O_EXCL, 0600) = 3 unlink("/tmp/PerlIO_WFvCgM") = 0 open("/tmp/PerlIO_su06bT", O_RDWR|O_CREAT|O_EXCL, 0600) = 3 unlink("/tmp/PerlIO_su06bT") = 0 open("/tmp/PerlIO_HAAg8Z", O_RDWR|O_CREAT|O_EXCL, 0600) = 3 unlink("/tmp/PerlIO_HAAg8Z") = 0 Use of uninitialized value in open at ./799021.pl line 32. open("", O_WRONLY|O_CREAT|O_TRUNC, 0666) = -1 ENOENT (No such file or +directory) ...

    Probably some special handling when the file name is an explicit scalar variable as opposed to just an undefined value...

    (This is generally documented:

    As a special case the 3-arg form with a read/write mode and the third argument being "undef": open(TMP, "+>", undef) or die ... opens a filehandle to an anonymous temporary file.

    but it doesn't say anything about what happens if the undef isn't written literally...)

      No explanation (yet),

      You end up at one of these:

      PerlIO * PerlIO_openn(pTHX_ const char *layers, const char *mode, int fd, int imode, int perm, PerlIO *old, int narg, SV **args) { if (narg) { if (narg > 1) { Perl_croak(aTHX_ "More than one argument to open"); } if (*args == &PL_sv_undef) return PerlIO_tmpfile(); ...
      PerlIO * PerlIO_openn(pTHX_ const char *layers, const char *mode, int fd, int imode, int perm, PerlIO *f, int narg, SV **args) { dVAR; if (!f && narg == 1 && *args == &PL_sv_undef) { if ((f = PerlIO_tmpfile())) {

      Notice how they check if the file name SV is the global constant undef (*args == &PL_sv_undef) rather than checking if it's undefined (SvOK(*args)).

      It could be a bug, but I suspect it's intentional to try to detect the case where the file name is accidentally undef. It almost never makes no sense for a program to allow both a valid file name and undef. If your program is one of those, you can use

      open(my $fh, '+>', $fn // undef)

      I think they should used a special character in the mode string instead of using a literal undef.

      but it doesn't say anything about what happens if the undef isn't written literally...)

      True, but one doesn't expect a difference in behaviour between the undefined value returned by undef and an undefined scalar. Any differences should be explicitly stated.

Re: open undef shift
by jakobi (Pilgrim) on Oct 03, 2009 at 16:19 UTC

    What I see is this:

    1. the final $yund is an actual undefined use caught by strict, the others instances don't try to actually use an undefined variable, consider e.g. the shift. my $tmp; $tmp and ... is fine, $tmp."1" is not.

    2. probably not what surprised you, but still: man perlop, at the beginning: operator precedence of 'or' is lower than of ','. Add parens to huh4 if this is surprising: or actually has the lowest precedence of all. Another variant: perl -e 'print "a" and print "b"'

    2b. use warnings stops on the use of $yund, before the open, w/o use warnings we get "No such file".

    3. but what surprises me is that this doesn't happen with huh3/huh31, maybe a bit later _inside_ open. Answer:

    perldoc -f open:
    As a special case the 3-arg form with a read/write mode and the third +argument being "undef": open(TMP, "+>", undef) or die ... opens a filehandle to an anonymous temporary file. Also using "+ +<" works for symmetry, but you really should consider writing something to the temporary + file first. You will need to seek() to do the reading.

    4. What does huh4 with an explicit assignment $yund=undef? Unchanged.


    5. A bit of an annoying difference between an variable interpolation of an undefined variable vs. undef as the result of an expression other than a basic variable.

    Maybe something like 'if value is from a real expression, just use it'. But if it's a variable, the argument to open does interpolation and get's the error. But I think it's a bit worse: w/o use warnings, open() in huh4 gets "" as argument (2b above; "" being the interpolated value for undef) instead of undef (3, eveything but huh4). I did not expect the extra interpolation for huh4.

    Any takers for digging into the C source to point out my mis-assumptions in this explanation attempt? Thanx :)


    Thanx to the opener for spotting this nice riddle

Re: open undef shift
by AnomalousMonk (Archbishop) on Oct 03, 2009 at 16:54 UTC
    Another variant to consider:
    >perl -wMstrict -le "sub huh41 { my $nullstring = ''; my $huh = open my $fh, '>', $nullstring or die $!; $huh += print $fh 'huh1'; $huh += close $fh; } print huh41(); " No such file or directory at -e line 1.
      The OP wasn't clear, but I believe the question is "Why do some means of obtaining an undefined value behave differently than others?" (answer), and perhaps "What happens when one passes undef as the file name to open?" (answer).
        My intention was only to offer another datapoint.

        I found it interesting that a lexical scalar initialized to the empty string behaved the same (minus the warning) as a virgin lexical. This behavior seems reasonably explained in ikegami's Re^2: open undef shift above.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://799021]
Approved by planetscape
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (7)
As of 2024-04-16 10:16 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found