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

I am writing a module for Remote Input-Output and I want to overload the diamond operator. How can I do it?

Follows an example of "how to use" this potential overload:

# Create a new SSH connection object to 'somehost.domain' $machine = GRID::Machine->('somehost.domain'); # Create a remote file my $file = $machine->open("foo.txt"); # I want the diamond to work my @x = <$file>;

Thanks

Casiano

Replies are listed 'Best First'.
Re: Inheritance and IO
by betterworld (Curate) on Jul 22, 2007 at 11:17 UTC
    This is an example for overloading the diamond operator:
    use overload '<>' => sub { return shift @{shift()}; }; my $obj = bless [ "hello", "world" ]; while ( defined( my $line = <$obj> ) ) { print "it says: $line\n"; }
    I suggest having a look at "perldoc overload" for more information.

    Update: Expanded my example code

    According to the documentation, using the overloaded operator in list context (as you intend to do) is not really supported.

      Thank you very much for your advice. It works
Re: Inheritance and IO
by almut (Canon) on Jul 22, 2007 at 12:05 UTC

    If I'm understanding you correctly, you could also have $machine->open("foo.txt") return a tied filehandle. From perldoc perltie:

    A class implementing a tied filehandle should define the following methods: TIEHANDLE, at least one of PRINT, PRINTF, WRITE, READLINE, GETC, READ, and possibly CLOSE, UNTIE and DESTROY. The class can also provide: BINMODE, OPEN, EOF, FILENO, SEEK, TELL - if the corresponding perl operators are used on the handle.

    As I understand it, READLINE would be called for the diamond operator:

    READLINE this

    This method will be called when the handle is read from via <HANDLE>. The method should return undef when there is no more data.

      Thanks almut.

      I suppose this will work in any context but it seems to require more programming effort :-(

        It's not that much effort :)   You could start with just the READLINE method, and add more functionality later, if the need should arise...

        Here's a simple example implementing READLINE and PRINT functionality:

        #!/usr/bin/perl package MyFH; sub TIEHANDLE { my $class = shift; return bless { @_ }, $class; } sub READLINE { my $self = shift; print "reading line from remote file $self->{file} ...\n"; # ... (your implementation here) my $line = "foo\n"; my @lines = ("foo1\n", "foo2\n"); return wantarray ? @lines : $line; } sub PRINT { my $self = shift; print "writing line(s) to remote file $self->{file} ...\n"; # ... (your implementation here) print "wrote: @_\n"; } package main; use Symbol 'gensym'; my $fh = gensym(); # get ref to anonymous glob tie *$fh, "MyFH", "file" => "foo.txt"; my $line = <$fh>; print "read: $line\n"; print $fh "bar", "baz";

        Outputs:

        reading line from remote file foo.txt ... read: foo writing line(s) to remote file foo.txt ... wrote: bar baz

        (Similarly, you could make use of Tie::Handle / Tie::StdHandle)

         

        Update: the benefit of using a tied filehandle would also be that you could more easily make your remote SSH connection handle act like a full-fledged drop-in replacement for a regular filehandle, so existing code making use of <$fh> and print $fh ..., etc. wouldn't have to be modified. This might not seem important now, but who knows when you'll need it...

        While you can overload the diamond operator, attempting to override/redefine print would soon turn into a major show stopper. Problem is that the print built-in doesn't have a prototype, at least not one that you could express with Perl's current prototyping mechanism (for this reason prototype 'CORE::print' is returning undef, btw). Its implicit prototype has been coded right into Perl's parser. This means that you cannot write a regular Perl subroutine which would be treated syntactically like the built-in print. In particular you can't get the "comma being absent" after the $fh in print $fh @args to work as desired (you'd get a syntax error if you tried).  With a tied filehandle you don't have such problems.

        Using a tied filehandle is the 'correct' approach as others have pointed out. It's not much work if you use the (more or less undocumented) Tie::StdHandle class in Tie/Handle.pm. Just subclass Tie::StdHandle and then implement the routines you need, probably OPEN and READLINE in your case.