On Thu, 2005-05-05 at 12:31, Larry Wall wrote:
> On Thu, May 05, 2005 at 10:14:34AM +0300, Gaal Yahas wrote:
> : On Wed, May 04, 2005 at 11:44:58PM -0700, Larry Wall wrote:
> : > : How do I open a file named "-"?
[...]
> : >     $fh = io("-");
> : >     $fh = open "-";

> : My concern is again with magic control. I've no gripes with the first
> : or last of those, but I think the second should not be allowed by
> : default.

> I think that, as with various other parts of Perl 6, we can try
> to sweep all the dwimmery into one spot so that it can be easily
> recognized and/or avoided.  And the default "open" is not the place
> for dwimmery.

I've been thinking about this particular thing ever since I wrote
File::Copy, and wanted it to accept filenames, magical file-like strings
or filehandles. Of course, that problem is easy in P6, but as I've been
thinking about my dream IO type system in Perl for so long, I have a few
opinions on it ;-)

Dash this all on the rocks if you want, but understand that this is not
an off-the-cuff reply, but something that I've spent a lot of time
mulling over, and I really think Perl 6 programmers everywhere would
enjoy such functionality. I'll even go so far as to offer to write it
once Pugs is in a state that allows for such.

First off, IMHO, open should be an alias for a closure-wrapped
constructor, like so:

        sub open := IO.new;

Pardon me if sub isn't the right tool there, I'm really not sure. The
point there is to make open have the same signature(s) as the
constructor(s) for IO. This allows you to instantly introduce every
variant of open you'll ever want. This makes "open" the maximally
dwimish operator. You can always introduce a "sysopen" and "stdiopen"
and "sockopen", etc. if you want domain-specific behavior exclusively
(e.g. treat everything as a filename only, or as a host:port only, etc).

Next, we need IO to be capable of understanding not only polymorphism:

        sub File::Copy::copy(IO $file1, IO $file2) {...}
        File::Copy::copy(IO::File.new($path1,:mode<read>),
                        IO::File.new($path2,:mode<write>));

but we also wish to be able to say:

        File::Copy::copy(IO.new("-"),IO.new("-"));

and perhaps even

        File::Copy::copy("-","-");

and have the right thing happen (right thing not always being a
universal for every program). How can we do this? Well, first IO has to
accept a string for the constructor:

        class IO is ParrotIO { # ParrotIO? not sure ...
                method new(Str $string) {...}
        }

I will assume that we upgrade types based on constructor signatures by
constructing a temporary, though I honestly don't recall that being said
explicitly in A12.

That's all well and good, but how does IO know about its children? They
might not even be loaded yet. You could just assume that any string
constructor is either an IO::Handle (if it's "-"), an IO::Pipe (if it's
"|"), or an IO::File otherwise, but that's a bit restrictive. What if we
decide we want URIs to be readable things? It would be nice to be able
to mix that in.

Sure enough, there's an easy way:

        class IO is ParrotIO does RegisteredStringConstructor {...}
        role RegisteredStringConstructor {
                has %:registry;
                sub register(Any $pattern, Type $type) {
                        %:registry{$pattern} = $type;
                }
                multi method new(Str $string,*%rest) {
                        for %:registry.keys -> $pat {
                                if $string ~~ $pat {
                                        return 
%:registry{$pat}.bless(:string($string),*%rest);
                                }
                        }
                }
        }

Now, IO::URI can say:

        class IO::URI is IO {
                use URI;
                IO.register(rx{^ <URI::ProtocolScheme> :}, ::IO::URI);
                ...
        }

and then you can:

        my $fh = open("gnomevfs:spreadsheet:/home/me/sheet.gnumeric",:r);
        while =$fh -> $row {
                say $row[0];
        }

Of course, my example URI brings up a host of questions, and probably is
incorrect gnomevfs syntax, but you get the idea.

Optional export features of IO::* could allow:

      * pipeline command execution
      * thread and/or process coupling
      * handle duping
      * much more

Thus, you would control these features like so:

        use IO;
        use IO::Funky :register_string_open_funkiness;
        open("funk",:w);

Now, if someone can just figure out how to re-write the string
registration so that it "behaves itself" (that is, unregisters when the
use goes out of scope), I think it would be perfect.

-- 
Aaron Sherman <[EMAIL PROTECTED]>
Senior Systems Engineer and Toolsmith
"It's the sound of a satellite saying, 'get me down!'" -Shriekback


Reply via email to