Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dealing with invalid filehandles (and maybe other invalid objects too)

As indicated by Tom Browder in this issue, the $*ARGFILES dynamic variable might contain invalid filehandles if any of the files mentioned in the command line is not present.

for $*ARGFILES.handles -> $fh {
    say $fh;
}

will fail with and X::AdHoc exception (this should probably be improved too):

Failed to open file /home/jmerelo/Code/perl6/my-perl6-examples/args/no-file: No such file or directory

The problem will occur as soon as the invalid filehandle is used for anything. Would there be a way of checking if the filehandle is valid before incurring in an exception?

like image 885
jjmerelo Avatar asked Feb 03 '19 09:02

jjmerelo


2 Answers

You can check if something is a Failure by checking for truthiness or definedness without the Failure throwing:

for $*ARGFILES.handles -> $fh {
    say $fh if $fh;  # check truthiness
    .say with $fh;   # check definedness + topicalization
}

If you still want to throw the Exception that the Failure encompasses, then you can just .throw it.

like image 89
Elizabeth Mattijsen Avatar answered Nov 18 '22 04:11

Elizabeth Mattijsen


TL;DR I thought Liz had it nailed but it seems like there's a bug or perhaps Ugh.

A bug?

It looks like whenever the IO::CatHandle class's .handles method reaches a handle that ought by rights produce a Failure (delaying any exception throw) it instead immediately throws an exception (perhaps the very one that would work if it were just delayed or perhaps something broken).

This seems either wrong or very wrong.

Ugh

See the exchange between Zoffix and Brad Gilbert and Zoffix's answer to the question How should I handle Perl 6 $*ARGFILES that can't be read by lines()?

Also:

  • https://github.com/rakudo/rakudo/issues/1313

  • https://github.com/rakudo/rakudo/search?q=argfiles&type=Issues

  • https://github.com/rakudo/rakudo/search?q=cathandle&type=Issues

A potential workaround is currently another bug?

In discussing "Implement handler for failed open on IO::CatHandle" Zoffix++ closed it with this code as a solution:

.say for ($*ARGFILES but role {
    method next-handle {
        loop {try return self.IO::CatHandle::next-handle}
    }
})

I see that tbrowder has reopened this issue as part of the related issue this SO is about saying:

If this works, it would at least be a usable example for the $*ARGFILES var in the docs.

But when I run it in 6.d (and see similar results for a 6.c), with or without valid input, I get:

say not yet implemented

(similar if I .put or whatever).

This is nuts and suggests something gutsy is getting messed up.

I've searched rt and gh/rakudo issues for "not yet implemented" and see no relevant matches.

Another workaround?

Zoffix clearly intended their code as a permanent solution, not merely a workaround. But it unfortunately doesn't seem to work at all for now.

The best I've come up with so far:

try {$*ARGFILES} andthen say $_    # $_ is a defined ArgFiles instance
                 orelse  say $!;   # $! is an error encountered inside the `try`

Perhaps this works as a black-and-white it either all works or none of it does solution. (Though I'm not convinced it's even that.)

What the doc has to say about $*ARGFILES

$*ARGFILES says it is an instance of

IO::ArgFiles which is doc'd as a class which

exists for backwards compatibility reasons and provides no methods.

And

All the functionality is inherited from

IO::CatHandle which is subtitled as

Use multiple IO handles as if they were one

and doc'd as a class that is

IO::Handle which is subtitled as

Opened file or stream

and doc'd as a class that doesn't inherit from any other class (so defaults to inheriting from Any) or do any role.

So, $*ARGFILES is (exactly functionally the same as) a IO::CatHandle object which is (a superset of the functionality of) an IO::Handle object, specifically:

The IO::CatHandle class provides a means to create an IO::Handle that seamlessly gathers input from multiple IO::Handle and IO::Pipe sources. All of IO::Handle's methods are implemented, and while attempt to use write methods will (currently) throw an exception, an IO::CatHandle is usable anywhere a read-only IO::Handle can be used.

Exploring the code for IO::CatHandle

(To be filled in later?)

like image 3
raiph Avatar answered Nov 18 '22 04:11

raiph