-
-
Notifications
You must be signed in to change notification settings - Fork 372
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IO::Path.dir failure listifies not-fatally on error #2650
Comments
Fixed with 38f4b7b |
Thanks! |
Some discussion here: 38f4b7b#commitcomment-32644165 |
Marked as blocker to make sure we make a proper decision on this as soon as possible. |
In general, if something is returing an Iterable, we throw rather than fail to prevent exactly the problem that R#2650 describes. Is spectest clean, so we weren't too strict about this anyway.
@Leont, there are simple options if you need the potential returned my @foo = '/var/spool/cups'.IO.dir.self; # Filter the Failure, throwing it. my Str @foo = '/var/spool/cups'.IO.dir; # Use a typed Array use fatal; # Make Failures thrown at return point
my @foo = '/var/spool/cups'.IO.dir; Do you have any reason not to consider acceptable all those options? |
No one ever wants a list containing a single
This is not and edge-case. This is a perfectly normal thing to expect to work. "You can't safely store the results of the dir method into an array unless you do X" is not something one can explain to end-users. Not for any value of X, even if there are three of them. |
I agree with you that this isn't an edge case. I know that, to many ones, the concept of But the fact is that in Perl6 "You can safely store the result of the foo method into any container, but be aware that if the method fails, the returned/stored value will be a Failure, unless you do X" is a perfect thing to explain to end-users, more over if I give them three Xs. (The only use of the So, why the I understand that there are lot of cases when the only sensible thing to do is to thrown an But in this case, a simple method call that can fail, with a my @foo = '/nousch'.IO.dir // (); # @foo ~~ Empty or with '/var/spool'.IO.dir -> @foo {
#Process @foo
} else {
.fail; # Propagate Failure to caller
} With all respect, your emphatic "No One, Never", sound to me as an attempt to impose to others your preferred paradigm. |
The very first sentence of the documentation for dir is "Returns the contents of a directory as a lazy list of IO::Path objects…".
I don't. I expect an exception when
Please do explain? I don't think I'm imposing any paradigm on anyone; I'm defining a requirement, not a solution. |
This is some problem-solving material right there. Putting We need that to be written down somewhere, and we should consistify things that don't follow what we end up writing down. |
Certainly, present documentation, as a work-in-progress and written by volunteers, in many cases lacks required rigour, favoure well established paradigms over new ones and omit important details misleading user expectations. Surprises me that Exceptions, a "Fundamental topic" don't even mention This discussion is about expectations, so let me explain:
To expect that To expect that an So, how the possible exception can be propagated to the caller?
Yes, indeed, but that imposes the user the use of a particular handling paradigm. And, as one of your proposed solutions, to me that situated your in the "what to impose" camp.
I don't know what do you mean with a Wrapping the Exception in a Failure and returning it, is another way, that allows the user to choose his preferred paradigm. While putting a I totally agree with @AlexDaniel than all this most be consensed, clear criteria established, and consistently implemented and documented. In my opinion, for example, specific iterators (strict-typed ones), when in the middle of the iteration, should thrown exceptions, but routines not able to create the |
That much is quite clear :-) |
I think this would do what we both want:
Changing
Choice is a good thing, but not at the cost of basic usability.
I'm not sure I understand you here.
The final error I got was «Type check failed in binding to parameter '$path'; expected IO::Path but got Failure». The old semantics fail at a distance (pun not intended), and that is a problem. |
Nope, 38f4b7b cannot be reverted atm as adding an |
Making |
There is some spooky action at a distance going on. If the first argument of the
Similarly bizarrely these both fail:
This one does succeed though:
It would appear Test.pm isn't entirely |
The second case has been clarified, it's the implicit I'm not entirely sure which behavior is desirable, but I'm pretty sure consistency is. |
Again, seems to me that you are testing your expectations. use Test;
my @foo = (Failure.new("")); throws-like { @foo[0] }, Exception, "Does throw" vs use Test;
my @foo = (Failure.new("")); throws-like { @foo[0].sink }, Exception, "Does throw" Note the difference. |
Maybe you should read the test that @lizmat mentioned before making assumptions #notamused.
I understand fully the difference. I think you completely missed my point. |
Let me rephrase the point:
|
I read all tests involved, and I'm against latest @lizmat's 23fca8f6fb because: a) It doesn't solve this issue, b) favoured one specific paradigm and c) introduces another inconsistency: for Failure.new { .perl.say } # Throws
for Failure.new, Failure.new { .perl.say } # Succeds #notamused either.
As I think you completely missed mine: A
No, the quoted form die because it attempt to coerce $failure to Str, one specific and documented case for throwing. BTW |
Extra data-point: this succeeds:
whereas this fails:
(the difference is the last line) |
Are you at the REPL, right?, please try: sink {
class MyFailure is Failure does Iterable { method iterator { note 'called'; self.self } };
my $foo = MyFailure.new("XXX"); say 'alive';
EVAL '$foo';
} And then sink {
class MyFailure is Failure does Iterable { method iterator { note 'called'; self.self } };
my @foo = MyFailure.new("XXX"); say 'alive';
EVAL '@foo[0]';
} ( Edit: Both cases thrown, the first because toplevel sink, the second inside de role because the self, the last line don't even play. |
D'oh! |
@Leont, |
Fixes R#2650. Makes .iterator throw immediately. There was some discussion on #perl6-dev on whether or not to have .iterator just return self, rather than throwing. But that would just delay the throwing until the FALLBACK of Failure would catch the "pull-one", which felt as just wasting extra cycles. In the past, code was changed for similar situations to throw the exception. This change should allow us to actually just return the Failure. This causes some breakage in S03-operators/minmax.t, as the test for failure is now thrown earlier and the tests don't expect that.
Added |
So Raku/roast@75132b8 either needs to be cherry-picked into 6.d-errata, or the rakudo commits need to be reverted.
|
OK, I cherry-picked it. From my point of view, Blin was clean so not much should be affected by this change. I'm a bit surprised that these are the only tests that need tweaking, but maybe the change is not as significant as it seems. Also, it's only the 6.d-errata that needs tweaking. |
Having just read through this, Alex's message, and the associated commits, I think this should be closed. |
The Problem
IO::Path.dir returns a
Failure
. This works fine when put directly in afor
loop, but when assigned to an array this doesn't quite DWIM.Expected Behavior
An exception is thrown
Actual Behavior
An array with a single Failure member is created
Steps to Reproduce
my @foo = "/var/spool/cups".IO.dir; dd @foo
Suggested solutions:
Either:
Environment
Rakudo 2018.12
The text was updated successfully, but these errors were encountered: