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

Hi

I just stumbled across an (for me) very unexpected behaviour with open:

use strict; my $file; open my $fh, "<", $file or die $!; print "here\n";
This prints "no such file or directory", as expected.

But

use strict; open my $fh, "<", $ARGV[0] or die $!; print "here\n";
This prints "here" - i.e. does not raise an exception when called without command-line arguments.

And finally

use strict; open my $fh, "<", undef or die $!; print "here\n";
Also does not raise an exception.

What is going on here?

I am using 5.26.1.

Many thanks!

Replies are listed 'Best First'.
Re: open undef
by ForgotPasswordAgain (Vicar) on Aug 02, 2018 at 17:57 UTC
    Looks like it's documented in open and creates a (useless in this case) anonymous temporary file.. (Try printing $fh->tell for example.) If the 3rd arg is undef, "opens a filehandle to a newly created empty anonymous temporary file. (This happens under any mode, which makes +> the only useful and sensible mode to use.)"
      I am not sure if this is documented as I open the file in read-mode, where this behaviour does not make any sense at all, but nevertheless very interesting.

      Can you explain then why the first case is different?

        When a Perl operator returns only true or false, it returns one of two statically-allocated scalars called &PL_sv_yes and &PL_sv_no. It's more efficient to return these than to allocate a new scalar every time.

        There's a third statically-allocated scalar: &PL_sv_undef. It's used by Perl when it needs to return undef.

        $ perl -MDevel::Peek -e'Dump(undef)' SV = NULL(0x0) at 0x2186148 REFCNT = 2147483639 FLAGS = (READONLY,PROTECT)

        This scalar is undefined because it has no OK flags. But notice the artificially high REFCNT that prevents it from being deallocated. This tells us that Perl returned &PL_sv_undef. I shall call this "the undef", in contrast to other undefined scalars which I'll call "an undef".

        An array element that has never been allocated (e.g. because nothing was ever assigned to it, or because delete was used on it) returns the undef.

        $ perl -MDevel::Peek -e'Dump($a[0])' SV = NULL(0x0) at 0x1116148 REFCNT = 2147483639 FLAGS = (READONLY,PROTECT)

        Otherwise, the array element itself is returned, which might be an undef.

        $ perl -MDevel::Peek -e'$a[0]=undef; Dump($a[0])' SV = NULL(0x0) at 0xc93f90 REFCNT = 1 FLAGS = ()

        The feature is meant to be triggered when you literally use undef in the code. But what it actually does is check for the undef.

        use feature qw( say ); my @a; { say open(my $fh, '<', $a[0]) ? 1 : 0; } # 1 $a[1] = undef; { say open(my $fh, '<', $a[0]) ? 1 : 0; } # 1 $a[0] = undef; { say open(my $fh, '<', $a[0]) ? 1 : 0; } # 0 delete($a[0]); { say open(my $fh, '<', $a[0]) ? 1 : 0; } # 1

        As you've discovered, this is an imperfect proxy.

        I am not sure if this is documented as I open the file in read-mode

        From open (emphasis mine):

        As a special case the three-argument form with a read/write mode and the third argument being undef:
        open(my $tmp, "+>", undef) or die ...
        opens a filehandle to a newly created empty anonymous temporary file. (This happens under any mode, which makes +> the only useful and sensible mode to use.)