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

$io->can('seek') == true, but $io->seek(pos, whence) == 'Illegal seek' - bug ?

by leriksen (Curate)
on Nov 15, 2004 at 03:42 UTC ( #407761=perlquestion: print w/ replies, xml ) Need Help??
leriksen has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to test a file handle that may be created from a file or from a 'piped open'. Now you cant seek on a file handle from piped open - its a stream, you get characters from the pipe, you cant jump 'backwards' or 'forwards'.

I thought I could test what kind of hadle I had by checking inheritance from IO::Seekable, or if the handle supported the 'seek' method - a file should, but a stream shouldn't.

But that doesn't seem to be the case - handles from 'piped open' say they inherit from IO::Seekable, and that they can('seek'), but if you do seek(), they fail.

Is that a bug ? Code and output follows

Code
#!/usr/bin/perl -w use strict; use IO::File; my $plain = IO::File->new('WEEK3.csv', O_RDONLY) or die "cannot open plain :: $!"; my $zipped = IO::File->new('unzip -qq -p WEEK3.zip |') or die "cannot open zipped :: $!"; print "plain IO::File\n" if $plain->isa('IO::File'); print "plain IO::Handle\n" if $plain->isa('IO::Handle'); print "plain IO::Seekable\n" if $plain->isa('IO::Seekable'); print "plain can seek\n" if $plain->can('seek'); print "zipped IO::File\n" if $zipped->isa('IO::File'); print "zipped IO::Handle\n" if $zipped->isa('IO::Handle'); print "zipped IO::Seekable\n" if $zipped->isa('IO::Seekable'); print "zipped can seek\n" if $zipped->can('seek'); use Fcntl qw(SEEK_END); if ($zipped->isa('IO::Seekable')) { print "seeking\n"; $! = 0; my $rc = $zipped->seek(0, SEEK_END); print "rc == $rc :: $!\n"; } $! = 0; if ($plain->isa('IO::Seekable')) { print "seeking\n"; <$plain>; my $rc = $plain->seek(0, SEEK_END); print "rc == $rc :: $!\n"; }

Output

plain IO::File plain IO::Handle plain IO::Seekable plain can seek zipped IO::File zipped IO::Handle zipped IO::Seekable zipped can seek seeking rc == :: Illegal seek seeking rc == 1 ::

use brain;

Comment on $io->can('seek') == true, but $io->seek(pos, whence) == 'Illegal seek' - bug ?
Select or Download Code
Re: $io->can('seek') == true, but $io->seek(pos, whence) == 'Illegal seek' - bug ?
by pg (Canon) on Nov 15, 2004 at 04:40 UTC

    If you look at the code for IO::File, you see this line:

    @ISA = qw(IO::Handle IO::Seekable Exporter);

    And in IO::FILE's document, it is also stated that: "IO::File inherits from IO::Handle and IO::Seekable. It extends these classes with methods that are specific to file handles.", so it is not a surprise that it inherits seek().

    We are looking at two totally different aspects here:

    1. Whether the object knows seek(). For sure it knows, if it is an IO::File;
    2. Whether it actually can successfully seek. Well, depends on, but it shall return the proper return code to indicate success or failure, which it did.

    I don't classify this as a bug, although a different person might design the class inheritance structure differently, so this could be handled in a more sophisticated and delicate way.

      So I guess one solution in IO::File is

      @ISA = qw(IO::Handle Exporter); ... if ( is_really_seekable() ) { # to be implemented splice @ISA, 1, 0, ('IO::Seekable'); # insert after IO::Handle }

      or such like - then $handle->can('seek') would work as expected...

      But it sounds like that has no chance of actually being accepted by P5P

      use brain;

        Sounds like you are trying to fix something little by introducing uncertainty to the inheritance structure, which could be viewed as a bigger issue.

        I don't see any issue with the current way seek() works. As long as the return code is correct, it shall not impact your ability to develop on top of it.

        pg explained that this interface change was not necessary, but I'd like to point out why I think it's actually a bad thing. I do not mean to rail against you or your idea, but I think this is a situation that demonstrates an important idea about system IO in general.

        First, I think it's helpful to explain that IO operations usually follow the pattern of just do it, followed by check if it succeeded. This is to prevent race conditions. If there is any time at all between when you check if you can do something, and when you actually try to do it, things could have changed. To prevent that, we just ask the operating system to do something for us. The operating system attempts to do it, and tells us if it succeeded or failed. That way, the operation is atomic. As far as we're concerned, it's one step, and thus there is no race condition.

        Your proposed interface violates this pattern. You may envision the seekability as simply a flag that is turned on or off depending on the filehandle type, but there are different factors that can affect the seekability. These factors can change moment to moment, so a filehandle may be seekable in general, yet still fail to seek at a specific moment. Even with your proposed change, one would still have to check seek's return value to be absolutely sure it worked, which negates the whole point of adding the seekability check.

        In short, an is_really_seekable function would invite race conditions, while presenting no descernable gain.

Re: $io->can('seek') == true, but $io->seek(pos, whence) == 'Illegal seek' - bug ?
by Zaxo (Archbishop) on Nov 15, 2004 at 04:57 UTC

    I suppose that is a buglet, if not a bug. It's not a very important one compared to the handiness of magic opening a pipe from a process and treating it like any other file handle.

    Your seekability tests just check that the IO::File object is also in IO::Seekable, which is always true. A better test might look like,

    sub IO::File::is_seekable { my $self = shift; eval { $self->seek( $self->tell()) }; not $@; }

    If you had gzipped files instead of zipped, I'd recommend the PerlIO::gzip layer. IIRC, that would make the handle seekable. Unfortunately, I don't know of a PerlIO layer for zip files.

    After Compline,
    Zaxo

Re: $io->can('seek') == true, but $io->seek(pos, whence) == 'Illegal seek' - bug ?
by ikegami (Pope) on Nov 15, 2004 at 05:08 UTC
    can doesn't check the properties of a file handle. can doesn't even know about file handles. can checks if the class or superclasses of an object has a method. Since $plain and $zipped are both IO::Files, can will return the same thing for both handles, no matter what the argument is.

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (2)
As of 2014-09-23 04:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (210 votes), past polls