develooper Front page | perl.perl5.porters | Postings from June 2003

Re: perlio: order of push operations in 3args open()

From:
Nick Ing-Simmons
Date:
June 26, 2003 03:25
Subject:
Re: perlio: order of push operations in 3args open()
Message ID:
20030626095655.1958.1@bactrian.elixent.com
Jarkko Hietaniemi <jhi@iki.fi> writes:
>Comments?
>
>----- Forwarded message from "Dintelmann, Peter" <Peter.Dintelmann@dresdner-bank.com> -----
>
>Subject: perlio: order of push operations in 3args open()
>From: "Dintelmann, Peter" <Peter.Dintelmann@dresdner-bank.com>
>Date: Wed, 25 Jun 2003 16:46:45 +0200
>Message-ID: <02596B2156160846AD0D4A90AF6B847D2F97BA@ffz00zaj.ffz00e.mail.dresdner.net>
>To: "'jhi@iki.fi'" <jhi@iki.fi>
>Return-Receipt-To: "Dintelmann, Peter"
>	 <Peter.Dintelmann@Dresdner-Bank.com>
>
>Hi Jarkko,
>
>assume you have three IO layers :via(test1) ... :via(test3) all having the
>same code:
>
>
>    package PerlIO::via::test1;
>
>    sub PUSHED
>    {   warn __PACKAGE__ . " pushed\n";
>        return bless {}, shift;
>    }
>
>    sub FILL
>    {   warn __PACKAGE__ . " fill ", caller, "\n";
>        return readline $_[1];
>    }
>
>    sub POPPED { warn __PACKAGE__ . " popped\n" }
>
>    1;
>
>Now we want to have an application reading data in the sequence
>
>    (app) <- test1 <- test2 <- test3 <- (file)

I like to draw those the other way round :-)

>
>This can be achieved with
>
>    open my $fh, "bla.txt" or die $!;
>
>    binmode $fh, ":via(test3)";
>    binmode $fh, ":via(test2)";
>    binmode $fh, ":via(test1)";
>
>    <$fh>;
>
>    close $fh;
>
>The output is (Win2K, ActivePerl 5.8 build 806)
>
>    PerlIO::via::test3 PerlIO::via::test3 rb GLOB(0x1a453f4) pushed
>    PerlIO::via::test2 PerlIO::via::test2 rb GLOB(0x1b9f3d8) pushed
>    PerlIO::via::test1 PerlIO::via::test1 rb GLOB(0x1b36ab0) pushed
>    PerlIO::via::test1 fill mainC:\h\doc\src\pl\dev\test4.pl32
>    PerlIO::via::test2 fill PerlIO::via::test1PerlIO/via/test1.pm10
>    PerlIO::via::test3 fill PerlIO::via::test2PerlIO/via/test2.pm10
>    PerlIO::via::test1 PerlIO::via::test1=HASH(0x1b36b34) GLOB(0x1b36ab0)
>popped
>    PerlIO::via::test2 PerlIO::via::test2=HASH(0x1b36ac8) GLOB(0x1b9f3d8)
>popped
>    PerlIO::via::test3 PerlIO::via::test3=HASH(0x1b9f384) GLOB(0x1a453f4)
>popped
>
>As expected the lowest layer is pushed first and the layers are popped in
>reverse order of the push operations.
>
>To get the same dataflow with open() let's try
>
>        open my $fh, "<:via(test3):via(test2):via(test1)", "bla.txt" or die
>$!;
>        <$fh>;
>        close $fh;
>
>and the output is
>
>    PerlIO::via::test1 PerlIO::via::test1 r pushed
>    PerlIO::via::test2 PerlIO::via::test2 r pushed
>    PerlIO::via::test3 PerlIO::via::test3 r pushed
>    PerlIO::via::test1 fill mainC:\h\doc\src\pl\dev\test4.pl32
>    PerlIO::via::test2 fill PerlIO::via::test1PerlIO/via/test1.pm10
>    PerlIO::via::test3 fill PerlIO::via::test2PerlIO/via/test2.pm10
>    PerlIO::via::test1 PerlIO::via::test1=HASH(0x1b9f378) GLOB(0x1b9f39c)
>popped
>    PerlIO::via::test2 PerlIO::via::test2=HASH(0x1b52258) GLOB(0x1b52288)
>popped
>    PerlIO::via::test3 PerlIO::via::test3=HASH(0x1b52378) GLOB(0x1b523a8)
>popped
>
>Compared to the result above the order of pushes is reversed. In particular
>pop operations are now executed in the same order as the push operations
>which
>looks strange to me.
>
>Am I doing some nonsense or is there a reason for the above behaviour?

There is a "reason" but perhaps not a very good one - see later.

Note that both ways of building the stack call the fills and the pops
in the same order - i.e. the same stack is built.

It is the pushes for the open case that are a little odd.
This is a side effect of fact that open tries to use the topmost layer 
to do the open, if that layer cannot do opens then it moves down the 
stack till it finds a layer that can. Assuming the open succeeds it then 
applies the layers it skipped over on the way down.
It does this with PerlIO_apply_layera() which would normally do them 
in the order you expect.

The snag is that PerlIO::via has to have an "open" entry in its function 
table in case your class has an OPEN method. So PerlIO_openn() sees that 
entry and gets PerlIO::via to do the open. PerlIO::via pushes itself 
and then discovers that there is no OPEN method. PerlIO::via then does
the same look-down the stack trick and gets a layer below to open 
the "PerlIONext(f)" slot. As that is also a via layer the same thing happens.

I guess with some thought PerlIO::via could be coded to not push itself
until it had established that there was an OPEN method, call lower open 
then push itself on top. That would give the push order you expect.

The question is whether it is worth making any promisses about the order
of pushes? 

You have noticed that 5.8.0 does it oddly, if we "fix" it in 5.8.0+ 
then if user-code cares it will be incompatible.

Another possibly more serious snag with the current code is when the 
via layer calls the ->PUSHED method in the open case the layer below 
is not the one it will eventually see, so if PUSHED tried to deduce 
anything about underlying layer(s) it would be mislead.
 


-- 
Nick Ing-Simmons
http://www.ni-s.u-net.com/




nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About