Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

IO::File vs CORE::open

by EvanCarroll (Chaplain)
on May 12, 2009 at 18:53 UTC ( #763565=perlmeditation: print w/ replies, xml ) Need Help??

A dispute, and finally a ban on irc.freenode.net/#perl, led me to investigate the differences between CORE::open and IO::File. The claim: both return the same thing. I was arguing to never use CORE::open, per the docs, experience, and for added clarity. In my eyes IO::File is more easily extended, and transparent in its operations.

Here is some of the conversation, I got a kickban, so I lost chanlogs. Lets try to clear it up.

11:43 <mauke> CORE::open is an interface to IO::Handle 11:43 <mauke> also, IO::Handle is from 5.003; three-arg open is from 5 +.6 11:44 <mauke> clearly open is more modern

It certainly isn't an interface *to* IO::Handle, at best it has some similarities to the interface *of* IO::Handle. Here is what the docs say on this. Now, that I read them, I can see how it is confusing.

File handles are now stored internally as type IO::Handle. The FileHandle module is still supported for backwards compatibility, but it is now merely a front end to the IO::* modules -- specifically, IO::Handle, IO::Seekable, and IO::File. We suggest, but do not require, that you use the IO::* modules in new code.
IO::Handle also touches on the fundamental differences between CORE::open's hack and itself.
Due to backwards compatibility, all filehandles resemble objects of class IO::Handle, or actually classes derived from that class. They actually aren't. Which means you can't derive your own class from IO::Handle and inherit those methods.
So I wrote a test on the two. For these tests, oofh is the filehandle opened with IO::File, while fh is the CORE::open version. Lets get some data! Comments added later.
## Two different reference types ok 2 - oofh is a reference ## though to an object. ok 3 - fh is a reference ## base type glob not ok 4 - they are the same reference ok 5 - oofh can call new() ok 6 - fh can call new() ok 7 - oofh can call new()->new() ## joy continues not ok 8 - fh can call new()->new() ## joy stops ## Both can do these, confusing isn't it... ok 9 - oofh autoflushed ok 10 - fh autoflushed ## But only one ->can('autoflush'), eh perl API I miss you. ok 11 - oofh can autoflush not ok 12 - fh can autoflush ## Only one is a true "object" ok 13 - oofh is an object per S:U:blessed() not ok 14 - fh is an object per S:U:blessed() ## But both are true filehandles ok 15 - oofh is an filehandle per S:U:openhandle() ok 16 - fh is an filehandle per S:U:openhandle() ## Revist test number #6 but with the byproduct of using IO::File to b +egin with. ## This one is amusing. not ok 17 - fh can call new wo/ IO::Handle loaded
I feel as strongly as ever, even though I didn't know fh's with CORE::open could $fh->autoflush, that all FH should utilize IO::File, and not CORE::open. The cause of this dispute was wanting to revise docs for novices. I argue for ignoring CORE::open. People shouldn't learn it first, if ever, in my eyes. If you want to revise the learning curve of perl, it is better to leave it out. The syntax is also scary for a lot of people. Who passes in a reference to a localized variable in a function anyway? If I wrote something that permitted silent failures and had a subroutine definition of.
sub _give_me_a_variable_to_hack_by_reference( my $foo );
Most programmers, perl and otherwise, would rightfully wtf me to oblivion. Also, what gives with a method call to a non-blessed-object, is there anything else in perl that breaks the API in such an unintuitive way? Oh you can find the test at http://gist.github.com/110655


Evan Carroll
www.EvanCarroll.com

Comment on IO::File vs CORE::open
Select or Download Code
Re: IO::File vs CORE::open
by ikegami (Pope) on May 12, 2009 at 19:23 UTC

    It certainly isn't an interface *to* IO::Handle,

    You can use it to calls methods in IO::Handle, so yeah, it is.

    <mauke> CORE::open is an interface to IO::Handle // also, IO::Handle is from 5.003; three-arg open is from 5.6 // clearly open is more modern

    Older = worse? nah, bad argument. The older module could be worse, but it's not because it's older.

    It's not like it's not maintained either. IO::File uses 3-arg open when possible.

    [Quoting IO::Handle,] Which means you can't derive your own class from IO::Handle and inherit those methods.

    That makes no sense. That's exactly what IO::File does.

    ok 3 - fh is a reference ## base type glob

    open's file handle *can* be a reference to a glob, but it can also be a glob.

    The glob can be magical (including tied) or not.

    The reference can be unblessed or blessed to any package.

    I feel as strongly as ever [...] that all FH should utilize IO::File

    I don't see where you explain why. What are the advantages of

    my $fh = IO::File->new($qfn, 'r') or die("Can't open file \"$qfn\": $!\n");
    over
    open(my $fh, '<', $qfn) or die("Can't open file \"$qfn\": $!\n");

    I have to load a module, create an object and learn a new permission notation just to end up calling open like I would anyway.

      Largely, the syntax of sending in a variable to retrieve an object is categorically obscure compared to the api that everyone else employs. No other module in perl, or on cpan, adopts a syntax that requires Class::constructor( my $obj, @args );. So purely for novices, as the exercise demands, it is far easier to comprehend the workflow without this oddity. Secondly, as I've demonstrated, there are a ton of other oddities that pertain to the ''thing'' that CORE::open returns.

      I think you're looking at a cup half-full, when you should look at the cup-half empty. Stay with me here, the idea that you are saving the ``use IO::Handle;`` is absolutely a bad idea!! This means that the environment of your code could be dependent on other things that you're not consciously controlling. If you use a module that indirectly uses IO::Handle anywhere, like IO::File, or something, and then you remove that and go back to CORE::open, you'll find all of your autoflush's don't work. This can break in runtime.
      This dies unless something, somewhere loads IO::Handle somehow. And, it doesn't have to be you. The kicker is while CORE::open *can* depend on IO::Handle, and while it is based off of the interface of IO::Handle, it doesn't pull it in. This leads me to conclude any functionality LIKE IO::Handle, that isn't implemented by using IO::Handle is duplicated somewhere, somehow; most probably implemented with a giant C dragon internally.

      open(my $fh, '<', $qfn); $fh->autoflush
      This always succeeds:
      use IO::Handle; open(my $fh, '<', $qfn); $fh->autoflush

      You also failed to address the inconsistencies between CORE::open() and IO::File->new() which my post hits on. They simply don't return the same thing, and where they differ CORE::open() is the one that is wrong.

      Furthermore, this obscure CORE syntax makes getting subclassing-like functionality awkward because now you have to consciously assume that $fh is real object that can be re-blessed, rather than simply look up the @ISA chain to get the $self..

      The much less surprising example with IO::File:
      use base 'IO::File'; ... sub new { my ( $class, @args ) = @_; my $exists = -e $args[0] ? 1 : 0; my $self = $class->SUPER::new( @args ); $data{$self} = { existed_when_opened => $exists , original_location => $args[0] }; $self; };
      Mauke's example with CORE::open, implicitly assumes CORE::open() will always return an object that is reblessable that has an api like IO::Handle:
      sub new { my ( $class, @args ) = @_; my $exists = -e $args[0] ? 1 : 0; open my $self, $args[1], $args[0]; ## yes, wtf -- major. bless $self, $class; $data{$self} = { existed_when_opened => $exists , original_location => $args[0] }; $self; }
      UPDATE: I just wanted to rephrase this explicitly, unless you know how CORE::open differs from IO::File, as of perl v5.10: I suggest you always use IO::File. Or, alternatively at the least use IO::Handle when you use CORE::open. You won't know when you've hit on the functionality that either you or CORE::open depends on. You'll just know it when IO::Handle isn't there...


      Evan Carroll
      www.EvanCarroll.com

        This dies unless something, somewhere loads IO::Handle somehow.

        So will

        my $fh = IO::File->new(...);

        if you don't do

        use IO::File;

        There goes half your node.

        No other module in perl, or on cpan, adopts a syntax that requires Class::constructor( my $obj, @args );

        What about builtins? open, opendir, tie, dbmopen, pipe, accept and connect.

        You could even include my, local, our and state as well, although they also return the constructed variable.

        On CPAN, there's Win32::Process::Create for one.

        I'll grant you the that point, but I'll weight it low because we're all so familiar with open that the weirdness is gone. (If you're not that familiar, you will be. open is used in too many places.)

        that isn't implemented by using IO::Handle is duplicated somewhere,

        I don't know to what your pronouns refer, but I don't see why anything is duplicated. OO interface calls IO::Handle. IO::Handle calls builtins. No redundancy.

        You also failed to address the inconsistencies between CORE::open() and IO::File->new() which my post hits on. They simply don't return the same thing, and where they differ CORE::open() is the one that is wrong.

        I "failed to address" the "inconsistencies" because they are irrelevant. The only wrong one I see is test 7 (assuming the test is what I guess it is), and that's not an IO::File test.

        Furthermore, this obscure CORE syntax makes getting subclassing-like functionality awkward

        Subclassing something that isn't an object is awkward... You don't say! What does that even mean.

        Inheritance isn't the best choice for files anyway, whether using IO::File or not.

        Evan said:
        No other module in perl, or on cpan, adopts a syntax that requires Class::constructor( my $obj, @args );.
        Win32::Process::Create.

        I know because I once spent half a day mocking this awful interface.



        - Boldra
Re: IO::File vs CORE::open
by karavelov (Monk) on May 13, 2009 at 02:22 UTC

    The build-in "open" function has a tons of functionality that could not be replicated using IO::File. Opening file-system files is just one of the cases that CORE::open covers. There are a lot of other cases as: dup-ing a fh, opening fh to memory location, fork-ing a child and splicing it's STDOUT to opened fh (pipes) etc.

    In short, with just one function with its little idiosyncratic language for open modes you could do almost all the things you could do with all IO::* modules (except sockets). You could hate it but there are people that like it, for various reasons.

    I do not fully understand your proposition for stop using CORE::open and start using IO::File. But why not use instead IO::Pipe? Or IO::String?

Re: IO::File vs CORE::open
by chromatic (Archbishop) on May 13, 2009 at 07:42 UTC
    If you want to revise the learning curve of perl, it is better to leave it out.

    Explaining OO before demonstrating how to perform file operations is definitely a revision of Perl's learning curve, but I'm not sure it's a revision of Perl's learning curve in the "easier to learn" direction.

    If you want conceptual purity of a single programming paradigm, you don't want Perl.

      Depends on the direction you are coming from. If you're used to the results of the "Everything is an object" mantra, the IO::File will look more familiar. I'd rather have "similar things should look similar, different things look different" than "everything looks the same", though.

      Jenda
      Enoch was right!
      Enjoy the last years of Rome.

        If you're used to the results of the "Everything is an object" mantra, the IO::File will look more familiar.

        Yet how inconsistent with the rest of the core language.

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (10)
As of 2014-08-29 12:30 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The best computer themed movie is:











    Results (280 votes), past polls