I'm playing around with lines
which reads lines from the files you specify on the command line:
for lines() { put $_ }
If it can't read one of the filenames it throws X::AdHoc
(one day maybe it will have better exception types so we can grab the filename with a .path
method). Fine, so catch that:
try {
CATCH { default { put .^name } }
for lines() { put $_ }
}
So this catches the X::AdHoc
error but that's it. The try
block is done at that point. It can't .resume
and try the next file:
try {
CATCH { default { put .^name; .resume } } # Nope
for lines() { put $_ }
}
Back in Perl 5 land you get a warning about the bad filename and the program moves on to the next thing.
I could filter @*ARGS
first then reconstruct $*ARGFILES
if there are some arguments:
$*ARGFILES = IO::CatHandle.new:
@*ARGS.grep( { $^a.IO.e and $^a.IO.r } ) if +@*ARGS;
for lines() { put $_ }
That works although it silently ignores bad files. I could handle that but it's a bit tedious to handle the argument list myself, including -
for standard input as a filename and the default with no arguments:
my $code := { put $_ };
@*ARGS = '-' unless +@*ARGS;
for @*ARGS -> $arg {
given $arg {
when '-' { $code.($_) for $*IN.lines(); next }
when ! .IO.e { note "$_ does not exist"; next }
when ! .IO.r { note "$_ is not readable"; next }
default { $code.($_) for $arg.IO.lines() }
}
}
But that's a lot of work. Is there a simpler way to handle this?
To warn on bad open and move on, you could use something like this:
$*ARGFILES does role { method next-handle { loop {
try return self.IO::CatHandle::next-handle;
warn "WARNING: $!.message"
}}}
.say for lines
Simply mixing in a role that makes the IO::CatHandle.next-handle method re-try getting next handle. (you can also use but
operator to mixin on a copy instead).
If it can't read one of the filenames it throws X::AdHoc
The X::AdHoc
is from .open
call; there's a somewhat moldy PR to make those exceptions typed, so once that's fixed, IO::CatHandle
would throw typed exceptions as well.
It can't .resume
Yeah, you can only resume from a CATCH
block that caught it, but in this case it's caught inside .open
call and is made into a Failure
, which is then received by IO::CatHandle.next-handle
and its .exception
is re-.throw
n.
However, even if it were resumable here, it'd simply resume into a path where exception was thrown, not re-try with another handle. It wouldn't help. (I looked into making it resumable, but that adds vagueness to on-switch
and I'm not comfortable speccing that resuming Exception
s from certain places must be able to meaningfully continue—we currently don't offer such a guarantee for any place in core).
including -
for standard input as a filename
Note that that special meaning is going away in 6.d language as far as IO::Handle.open
(and by extension IO::CatHandle.new
) goes. It might get special treatment in IO::ArgFiles
, but I've not seen that proposed.
Back in Perl 5 land you get a warning about the bad filename and the program moves on to the next thing.
In Perl 6, it's implemented as a generalized IO::CatHandle
type users can use for anything, not just file arguments, so warning and moving on by default feels too lax to me.
IO::ArgFiles
could be special-cased to offer such behaviour. Personally, I'm against special casing stuff all over the place and I think that is the biggest flaw in Perl 5, but you could open an Issue proposing that and see if anyone backs it.