-
Notifications
You must be signed in to change notification settings - Fork 323
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
Propagate DataflowError in middle of block instead of ignoring it #11777
base: develop
Are you sure you want to change the base?
Conversation
"OK" | ||
|
||
suppress_error yes:Boolean value = | ||
yield_error yes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This 49c628e commit changes the behavior on this line:
- previously the
Error
returned fromyield_error
was ignored - previously the execution continued to next line and
value
was returned - now the
Error
is detected and execution of this method ends immediately with theError
To suppress such behavior one may simply prefix the call with a dummy _ = yield_error yes
assignment. As assignments always return Nothing
the block statement will be considered OK as the errorIsAssignedAndThatIsEnoughReturnValue
test demonstrates.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't we want assignment to also propagate errors in this way? This is another class of common missed errors, I would think. Only catch
should allow you to stop propagation, I would think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you elaborate and show some example where you think the behaviour is not what we want?
From my perspective, with the changes from this PR all is good - the dataflow errors flow with the dataflow, determined by dependencies between method calls. The problem was when the value was unassigned because the dataflow error would be lost unhandled. But if it's assigned to something, it should flow further and be propagated. Unless the name is unused - but we have 'unused warning' for that already.
I think that propagating 'more aggressively' upon assignment would make the dataflow error not much (if at all in practice?) different from a Panic. Also it may be problematic for the IDE. The whole point of dataflow errors is that they do not stop execution of other nodes if they are assigned to something, so that even if one node in the GUI errors, all the others can still be executed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assignment to also propagate errors in this way?
This is another class of common missed errors, I would think.
Can such an error be missed without a
we have 'unused warning' for that already.
warning being printed by the compiler? If not, then it is less critical scenario. Users get compilation warning and that might warn them enough.
Btw. I think there is a contra-example:
x = Error.throw "OK"
x . catch Any h->h
the second line wouldn't even be invoked.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@radeusgd I definitely see your point -- assignments like this form the top-level spine of the entire program, so this would prevent execution after a dataflow error. For that case, I agree. For an assignment with a regular method call, one that does not represent a top-level node (from the user's point of view), it's still something that could be lost.
@JaroslavTulach I see your point here as well. However, this case:
x = Error.throw "OK"
Will still mask errors, and hide them from the end user and the library developer. I don't have a suggestion for how to handle this, but it still should be handled. If something is called "error" then it should never be hidden.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mask errors, and hide them from ... the library developer
No, it won't hide them. There will be a warning about unused variable x
. E.g. library developer has been notified the code is smelly.
for (ExpressionNode statement : statements) { | ||
statement.executeGeneric(frame); | ||
var result = statement.executeGeneric(frame); | ||
if (result != nothing) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not get rid of this if statement and use simply just if (result instanceof DataflowError err)
. If it is an instance of DataflowError
, it cannot be nothing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed this seems redundant, can we remove it, or is there some reason that we don't see here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason is the other part of #5430:
- what should happen when the value is not
Nothing
- and it is not
DataflowError
(which is immediately returned) - Avoid discarded (error) values in runtime #5430 talks about such values, but
- I don't know what to do with them (they are not as simple as
DataflowError
) - related is Unexpected block behaviour with multiline operators #9944
We don't need to solve it in this PR. Just my 2 Kč explanation of the != Nothing
check. In any case, that's for another PR.
There are two failed tests in standard libraries: This is the kind of errors we can expect if we enable this Btw. this change makes the diff --git test/Base_Tests/src/Data/Decimal_Spec.enso test/Base_Tests/src/Data/Decimal_Spec.enso
index 3465ce9cd8..6e3a463b82 100644
--- test/Base_Tests/src/Data/Decimal_Spec.enso
+++ test/Base_Tests/src/Data/Decimal_Spec.enso
@@ -487,7 +487,7 @@ add_specs suite_builder =
(Decimal.from_integer 7297927982888383 . multiply (Decimal.from_integer 828737) (Math_Context.new 6)) . should_equal (Decimal.from_integer 6048060000000000000000 )
(Decimal.new "893872388.3535345" . multiply (Decimal.new "72374727737.23434535") (Math_Context.new 14)) . should_equal (Decimal.new "64693770738918000000")
- (Decimal.new "909678645268840" . divide (Decimal.new "28029830") (Math_Context.new 6)) . should_equal (Decimal.new "32453900 ")
+ _ = (Decimal.new "909678645268840" . divide (Decimal.new "28029830") (Math_Context.new 6)) . should_equal (Decimal.new "32453900 ")
(Decimal.new "384456406.7860325392609633764" . divide (Decimal.new "24556.125563546") (Math_Context.new 7)) . should_equal (Decimal.new "15656.23")
(Decimal.from_integer 3948539458034580838458034803485 . add (Decimal.from_integer 237957498573948579387495837459837) (Math_Context.new 20)) . should_equal (Decimal.from_integer 241906038031983160230000000000000) e.g. exactly as expected it is enough to add a dummy assignment and the problem goes away. I assume you want to do a better fix @GregoryTravis - please integrate it into my branch, so it gets green. diff --git test/Base_Tests/src/Data/Time/Date_Range_Spec.enso test/Base_Tests/src/Data/Time/Date_Range_Spec.enso
index b2b469ae1c..22843aa6cb 100644
--- test/Base_Tests/src/Data/Time/Date_Range_Spec.enso
+++ test/Base_Tests/src/Data/Time/Date_Range_Spec.enso
@@ -157,7 +157,7 @@ add_specs suite_builder =
r.partition p . should_equal (r.to_vector.partition p)
r.all p . should_equal (r.to_vector.all p)
r.any p . should_equal (r.to_vector.any p)
- r.find p . should_equal (r.to_vector.find p)
+ _ = r.find p . should_equal (r.to_vector.find p)
r.index_of p . should_equal (r.to_vector.index_of p)
r.last_index_of p . should_equal (r.to_vector.last_index_of p)
count_mondays acc date =
@@ -170,7 +170,7 @@ add_specs suite_builder =
r.partition fc . should_equal (r.to_vector.partition fc)
r.all fc . should_equal (r.to_vector.all fc)
r.any fc . should_equal (r.to_vector.any fc)
- r.find fc . should_equal (r.to_vector.find fc)
+ _ = r.find fc . should_equal (r.to_vector.find fc)
r.index_of fc . should_equal (r.to_vector.index_of fc)
r.last_index_of fc . should_equal (r.to_vector.last_index_of fc) same for |
…wrongly written test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Santa came early this year! 🎄
I'm so happy to finally see this change - deep down I knew we may be losing something due to the unhandled errors disappearing into the void. And you confirmed my suspicions. Thankfully that isn't that many errors and they look relatively harmless. But I'm happy that from now on I can keep writing code with the peace of mind that errors will go on unnoticed.
Also we can now remove most instances of if_not_error
- yay! 🎉 It was basically a workaround for ensuring error propagation. I guess we want to keep the function because it is still useful when we want to control the propagation with 'more precision'. But in numerous cases it should be no longer needed and we can remove a lot of unnecessary indentation from the code.
I submitted commits that fix should_equal
silently breaking if expected value provided is dataflow error (in that case should_fail_with
is expected). I will add a commit fixing the Date_Range_Spec
tests in a moment.
... we already published first customer releases and we are dedicated to backward compatibility, right? |
Engine benchmarks run is fine - looks like nobody writes benchmarks for errors ;-) I also glanced StdLib benchmarks run and found nothing suspicious. |
@radeusgd, @GregoryTravis there are still failures in stdlib tests: Can you fix them? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approving the libs bits.
…ateDataflowError5429
Except these two errors: There seem to be additional ones: |
I will look at these, after the release. |
Pull Request Description
Partially fixes #5430 by propagating
DataflowError
s found during statement execution out of the method.Important Notes
This change may affect behavior of existing methods that ignore
DataflowError
as discussed here.Checklist
Please ensure that the following checklist has been satisfied before submitting the PR:
Scala,
Java,