develooper Front page | perl.perl5.porters | Postings from February 2013

Re: Don't patch perlopentut: rewrite it completely

Thread Previous | Thread Next
Tom Christiansen
February 17, 2013 17:06
Re: Don't patch perlopentut: rewrite it completely
Message ID:
> It seems most of you haven't read what I wrote both on the mailing list and
> on irc at all.

I don't read IRC.

> There is a complete rewrite in progress already:

That seems to be too complicated for a tutorial whose mission 
is to teach people how to use open.

> The structure has been thought out by leont, I've started
> filling it with content.

> My goal was a simple modernization of perlopentut in form of replacing
> 2-arg with 3-arg open and bareword (what we call direct filehandles after
> some discussion in IRC) with lexical (what was called indirect filehandle
> before) filehandles to have at least *something* ready for 5.18 that
> doesn't teach newbies things that aren't best practice since over ten years.

First, you will note that I not only addressed both moderista shibboleths, 
your three-arg open and autovivved handles, but rather more in a short
and simple article.

They aren't lexical filehandles, you know; that's a misleading misnomer.

What you appear to care about is *autovivved* handles, a concept wholly 
orthogonal to the variable's *scope*.

1. This is *not* a lexical filehandle, but it *is* an autovivved one:

    use vars qw($GLOBAL);
    undef $GLOBAL;
    open($GLOBAL, "<", $path)
	|| die "can't open $path: $!";

2. This *is* a lexical filehandle, but it is *not* an autovivved one:

    my $fh = \*STDOUT;
    print $fh "Now you see it.\n";

See the difference?

A direct handle is the name of that handle.  It is only distinguishable
from a bareword by context.  This is like the actual name of a subroutine.

    somefunc();			    # name of function is "somefunc"
    print SOMEHANDLE "stuff\n";	    # name of handle   is "SOMEHANDLE"

An indirect handle is a scalar expression whose evaluation yields something
that can be used where an actual handle is called for, meaning one of a
string whose glob will be looked up in package symbol table; a typeglob; a
reference to a typeglob; or an I/O object.

This is like an indirect subroutine call, something whose evaluation
produces something that allows you to access the subroutine, either by its
symbol table entry or through a reference.   These are all indirect because
they use not the thing you need directly, but rather something that evaluates 
to what you need:

    $funcname = "somefunc";

    $funcaddr = \&somefunc;

    $fh_name = "SOMEHANDLE";
    print $fh_name "stuff\n";

    $fh_glob = *SOMEHANDLE;
    print $fh_glob "stuff\n";

    $fh_globref = \*SOMEHANDLE;
    print $fh_globref "stuff\n";

    $fh_ioobj = *SOMEHANDLE{IO};
    print $fh_ioobj "stuff\n";

    @fh = \( *STDIN, *STDOUT, *STDERR );
    print { $fh[$fdnum]      } "stuff\n";
    print { $fh[$ok ? 1 : 2] } "stuff\n";

    print { $ok ? \*STDOUT : \*STDERR } "stuff\n";

Autovivved handles are just like autovivved hashes and autovivved arrays.

An autovivved array or hash is an anonymous array or hash which is
implicitly allocated by Perl and whose reference is stored into the
previously undefined scalar lvalues when you attempt to use that lvalue 
to dereference it as though it were an actual array or hash.

    undef $aref;
    @$aref = ();

The scoping of the lvalue is immaterial to its autovivification.  What matters
is the implicit allocation, and the refcounting on the allocated object.

In just the same way, autovivved handles are anonymous handles allocated by
Perl whose references are stored in previously undefined scalar lvalues
when you attempt to use that lvalue in a place that expects to initialize a
handle.  Its scope is inconsequential to its autovivification.

What you want to call lexical filehandles is missing the essential point
of autovivification of anonymous handles, which has nothing to do with scope.

As before, it is the implicit, ref-counted allocation that matters.

  autoviv an array = allocate an anon array  and store its ref into undefined lvalue
  autoviv a  hash  = allocate an anon hash   and store its ref into undefined lvalue
  autoviv a handle = allocate an anon handle and store its ref into undefined lvalue

It's a bit more complicated than that, but there is no need to 
get into glob refs and I/O objects and dir- vs file-handles.  
It is enough to call it an anon handle and be done with it.

Filehandle autovivification occurs when any of the handle arguments
passed to these builtin functions is an undefined lvalue in any slot
whose argument name below begins with "AV_", but no others:

    open	(AV_FH,  args ...)
    sysopen	(AV_FH,  args ...)
    socket	(AV_FH,  args ...)
    accept	(AV_FH,  SERVER_FH)
    pipe	(AV_FH1, AV_FH2)
    socketpair	(AV_FH1, AV_FH2, args ...)

Additionally, handle autovivification occurs on the directory slot
of the I/O object with this function:

    opendir	(AV_DH,  path);

In contrast, handle autovivification does not occur on handle arguments 
to the these functions, because unlike those mentioned above, these below
do not initialize handles:

    bind, binmode, close, closedir, connect, eof, fcntl, fileno,
    flock, getc, getpeername, getsockname, getsockopt, ioctl, listen,
    lstat, read, readdir, readline, recv, rewinddir, seek, seekdir,
    select, send, setsockopt, shutdown, stat, sysread, sysseek,
    syswrite, tell, telldir, tie, tied, untie, write

> But instead of allowing a simple change that makes the document at least
> follow current best practises you start something that easily takes months.


This is a trivial document.  If it takes more than a day or two, then
something is being done wrong.  Define a sufficiently narrow scope that is
both necessary and sufficient to avoid endless mission creep, and it nearly
writes itself.

And has.


Thread Previous | Thread Next Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About