In Pharo (and other dialects) the ZeroDivide exception is resumable. Why?. For instance, if you evaluate 1 / 0 and then proceed, the answer is the ZeroDivide error. Why is this? Shouldn't ZeroDivide be not resumable?
EDIT:
Let's review this issue in more depth.
The problem here is that if the exception happens, what we get is the ZeroDivide exception. So, the only reason I can think of for making this exception resumable is to enable the following:
[a / b] on: ZeroDivide do: [:ex | ex resume: self anythingButTheQuotient],
right?
But this could have also be written
[a / b] on: ZeroDevide do: [self anythingButTheQuotient]
without requiring the exception to be resumable.
Resumable exceptions make sense if there is an "interesting" #defaultAction. But this seems not to be the case with ZeroDivide.
One could be tempted to say that in many cases one has this kind of code:
b = 0 ifTrue: [^0] ifFalse: [^a / b]
so why not using 0 as the #defaultAction? That would make the above code simpler (in those cases) and would only require a special handler in the (arguably) few ones that must behave differently. However, this would be a really bad decision because the default behavior would hide errors that, as we all know, the later they manifest the worst.
Yes, this is surprising at first sight, but the ANSI standard says:
Zero divide exceptions are resumable so any message in this protocol
that signal such an exception may ultimately return to their sender.
The example you gave was trivial, but when installing the handler a few methods above, it's less trivial to resume the exception where it was signalled.
[self doSomethingComplex]
on: ZeroDivide
do:
[:exception |
"Handle zero divide as inf/nan as if performed in floating point arithmetic"
exception resume: exception dividend asFloat / 0.0]
In Squeak or Pharo, see the references to signalContext instance variable in class Exception. You'll see that resuming is your sole option for returning control to the signaller.
Related
I am working on a problem that requires to optimize a double variable. I wrote a simple code to try it out that tries to find a number given an upper bound ( maximize X while X < upper bound), but I get the following error that I did not understand :
2022-11-13 09:59:07,003 [main] INFO Solving started: time spent (119), best score (-1init/0hard/0soft), environment mode (REPRODUCIBLE), move thread count (NONE), random (JDK with seed 0).
Exception in thread "main" java.lang.ClassCastException: class org.optaplanner.core.impl.domain.valuerange.buildin.primdouble.DoubleValueRange cannot be cast to class org.optaplanner.core.api.domain.valuerange.CountableValueRange (org.optaplanner.core.impl.domain.valuerange.buildin.primdouble.DoubleValueRange and org.optaplanner.core.api.domain.valuerange.CountableValueRange are in unnamed module of loader 'app')
at org.optaplanner.core.impl.heuristic.selector.value.FromSolutionPropertyValueSelector.iterator(FromSolutionPropertyValueSelector.java:127)
at org.optaplanner.core.impl.heuristic.selector.value.FromSolutionPropertyValueSelector.iterator(FromSolutionPropertyValueSelector.java:120)
at org.optaplanner.core.impl.heuristic.selector.value.decorator.ReinitializeVariableValueSelector.iterator(ReinitializeVariableValueSelector.java:58)
at org.optaplanner.core.impl.heuristic.selector.common.iterator.AbstractOriginalChangeIterator.createUpcomingSelection(AbstractOriginalChangeIterator.java:35)
at org.optaplanner.core.impl.heuristic.selector.common.iterator.AbstractOriginalChangeIterator.createUpcomingSelection(AbstractOriginalChangeIterator.java:10)
at org.optaplanner.core.impl.heuristic.selector.common.iterator.UpcomingSelectionIterator.hasNext(UpcomingSelectionIterator.java:27)
at org.optaplanner.core.impl.constructionheuristic.placer.QueuedEntityPlacer$QueuedEntityPlacingIterator.createUpcomingSelection(QueuedEntityPlacer.java:45)
at org.optaplanner.core.impl.constructionheuristic.placer.QueuedEntityPlacer$QueuedEntityPlacingIterator.createUpcomingSelection(QueuedEntityPlacer.java:31)
at org.optaplanner.core.impl.heuristic.selector.common.iterator.UpcomingSelectionIterator.hasNext(UpcomingSelectionIterator.java:27)
at org.optaplanner.core.impl.constructionheuristic.DefaultConstructionHeuristicPhase.solve(DefaultConstructionHeuristicPhase.java:45)
at org.optaplanner.core.impl.solver.AbstractSolver.runPhases(AbstractSolver.java:83)
at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:193)
at SimpleApp.main(SimpleApp.java:42)
The variable X has a range between 1 and 300, and the upper bound is an arbitrary 10.548
OptaPlanner intentionally avoids working with doubles. The documentation explains why, and also describes better ways of dealing with the issue.
That said, the exception you mention still shouldn't be happening, or there should be a more descriptive one. I'll eventually look into it. But my advice is to not count on doubles in your scoring function.
Today I've learned that in Pharo the execution of:
[v := 1] ensure: [self halt. v := 2]
will end up setting v = 2, even when we abandon the process at the halt window(!).
I find this debatable. For me, the semantics of #ensure: means that the sequence
self halt. v := 2
must be executed, regardless the circumstances with the receiver block, not regardless the logic of the argument block. And since the logic of #halt includes the event of terminating the process, I find it intrusive the obstinate evaluation of the second sentence.
Next I tried the following:
[v := 1] ensure: [1 / 0. v := 2]
When the ZeroDivide exception popped-up I closed the debugger and still the value of v was 2 (same as with #halt.)
Finally, I evaluated:
[v := 1] ensure: [n := 1 / 0. v := v + n]
and closed the debugger on the ZeroDivide exception. This time the value of v was 1 but I got no exception from the fact that v + n cannot be evaluated. In other words, the error went on silently.
So my question is. What's the rational behind this behavior? Shouldn't the process just terminate at the point it would terminate under "normal" circumstances, i.e., with no #ensure: involved?
Interesting one. It seems that your answer lies in the method BlockClosure>>valueNoContextSwitch, which is called by #ensure:. If you read the comment there, it says that it creates an exact copy of BlockClosure>>value (in a primitive), and the return value of that copy gets returned, not the return value of the original block containing your halt which you terminated. So the copy gets executed (apparently ignoring the copied halt), even if the original doesn't get to finish.
My guess is that this is intended to ensure (no pun intended) that the ensure: block always runs, but has the unintended side effect of ignoring the termination of the original block. I agree with you that this is not only counter-intuitive, but also probably not what was intended.
I guess this is behavior which is not fully defined by any (ANSI) standard, but correct me, if I am wrong.
Other Smalltalks seem to behave different. I tried it in Smalltalk/X, where the Debugger offers 3 options: "Continue" (i.e. proceed), "Abort" (i.e. unwind) and "Terminate" (i.e. kill the process). I guess "Terminate" corresponds to what Squeak does when you close the debugger.
With "Abort" and "Terminate", the rest of the ensure block is NOT executed, with "Continue" it is. I guess that is ok, and what you would expect.
On Abort and Terminate (which are both unwinds to corrsponding exception handlers), it should not try to reevaluate or proceed the potentially wrong/bad/failing ensure block.
It is be the choice of the handler (which the Debugger basically is) if it wants to proceed or not. If not, then it should get out of the ensure block and continue to execute any other ensure blocks which may be above in the calling chain.
This is consistent with the behavior of exception handling blocks, which are also not reevaluated or proceeded if the same exception is raised within. In ST/X, there is explicit code in the exception classes which cares for this situation, so it is definitely by purpose and not by side effect.
My guess is that this is wrong in Squeak and the Squeak developers should be told.
I posted a code example in previous question and here is critical part:
Try
first = _string.IndexOf(_firstchar) + 1
second = _string.IndexOf(_secondchar)
If first >= 1 And second >= 0 Then
retval = _string.Substring(first, second - first)
End If
Catch ex As Exception
End Try
One of experienced VB users say that such usage of Try/Catch is "evil".
Why is such usage "evil" and what is minimally enough to get program to continue when we don't want to bother with error?
An empty Catch block is evil since it can hide exceptions that you should handle. The Try-Catch is redundant here, you should use the overload with a start index for the second :
first = _string.IndexOf(_firstchar)
If first >= 0 Then
first += 1
second = _string.IndexOf(_secondchar, first)
If second >= 0 Then
retval = _string.Substring(first, second - first)
End If
End If
Note that you should use AndAlso instead of And.
The reason that is considered bad practice is because the exception you are catching there is not really handled in any way so it goes unnoticed. That in turn can cause other problems further down the program flow and those would be heard to gave back to the root cause, or even if traced, fixing them might be complicated by the previous decision to mask the error condition.
That said, there may be rare circumstances where it would be appropriate to swallow an exception like that. But if you do make that decision make sure to document the fact and state the reason you decided to ignore the error at that point.
For instance, it might be appropriate to ignore an exception that is triggered by a logging function. Since the purpose of the logger is to log the error, if for some reason the logging fails, there is probably not much else to do with that exception..
Consider the following class:
class Xyz {
public int count;
public void numZero (int[] x) {
// Effects: if x == null throw NullPointerException
// else return the number of occurrences of 0 in x
int count = 0;
for (int i = 1; i < x.length; i++) //we have a bug here
{
if (x[i] == 0)
{
count++;
}
}
this.count = count;
}
}
I'm trying to wrap my head about what Fault, Error and Failure really mean.
Fault
From what I've come to understand, a Fault in this context would be a flaw in the code's written logic.
So in this case the Fault would be the fact that the code instructs the computer to start iterating over all elements of v with a start index of 1 instead of the expected 0.
Error
When running the above method, we always get an Error but in once instance (when v.length == 0), as what we really want is to iterate over all elements of x, but since we're starting with i = 1, that is not really happening.
With an empty vector as input, as we don't enter the for loop, so our incorrect code isn't run, meaning that the Error doesn't happen, and everything happens as should in theory.
Failure
Since our code has a Fault that in execution-time will almost always manifest in a Error, we only have a Failure when we effectively see the incorrect output.
Assuming that an Error effectively happened in my program, we only have a Failure if it is in some way visible to the outside world. That is, had I private int count; instead of public int count; I'd never ever have an Error in my class (of course it'd be the most useless class ever!). Is this right?
Is everything I said correct or am I erring in something?
Thanks
Failure: A difference from the expected result. This is the problem
you observe.
Fault: The cause of the failure.
Error: The mistake which caused the fault to occur. e.g, typos.
An example of failure, fault and error.
pre: param is an integer.
post: returns the product of the param multiplied by 2.
1. int double (int param) {
2. int result;
3. result = param * param;
4. return result;
5. }
• A call to double(3) returns 9, but the post condition says it should return 6.
• Result 9 represents a failure.
• The failure is due to the fault at line 3, ( "* param" is used instead of "* 2")
• The error is a typo, ( someone typed "* param" instead of "* 2" by mistake).
Why give three different labels for a "Bug"?
They help communicate how precisely you know what the problem is.
Saying "failure" means you know something is wrong but don't know the cause.
Saying "fault" means you know the cause, but don't know why the fault occurred.
Saying "Error" means you know why the fault occurred; e.g.: The coder was distracted by a firetruck passing by.
You could ask, "But why did the person make a typo?" But that gets into into human factors and out of the scope of the question.
Source: Zhen Ming (Jack) Jiang - EECS 4413, Software Testing, York University.
First, a failure occurs whenever the actual service delivered by a system deviates from its expected service. Note that since even specifications can go wrong, the definition does not rely on them.
Second, an error is the part of the system state that may lead to a failure. The state of the system can go wrong but never reach the output, thus not lead to a failure.
Third, a fault is the cause of an error. It can be a design fault, a cosmic ray or whatever. If, as you point out, the fault is not activated, no error is produced.
Take a look at the basic concepts and terminology of dependability for more information.
Error is a deviation from the actual and the expected result. It represents the mistakes made by the people.
Faults are the result of an error. It is the incorrect step or process due to which the program or the software behaves in an unintended manner
Bug is an evidence of Fault in a program due to which program does not behave in an intended manner
Failure is an inability of the system or components to perform its required function. Failure occurs when Faults executes
Defect is said to be detected when Failure occurs.
There are a plurality of different definitions, the one I personally prefer is the following:
Fault -> Error -> Failure
Fault: The verified or hypothesized cause of an error (malfunctions, external interference, design errors).
Error: The manifestation of a fault within a program or data structure (difference between actual output and expected output).
Failure: The event that occurs when an error reaches the service interface, altering the service itself (leads to the inability of a system or component to perform required function according to its specification).
The Error in Error/Fault/Failure refers to the human error that introduced the problem. The human error was the incorrect thinking that caused the user to create an incorrect for statement in your example.
Errors are hard to measure or understand. It is difficult in many cases to know what the developer was thinking when the made the error that introduced the fault. That is why they like to differentiate between error and fault. We can see that there is a fault in the code, but it is hard to know why the error was created. It could be that the code was correct, and then during a subsequent change, the for loop was changed.
I always remember that an Error by a programmer leads to a fault in the code that results in a failure for the user. Not all errors result in a fault. Not all faults result in failures.
The software Fault refers to a bug in the code. And it is DURING the software activity.
While software Failure is when the system misbehaves. This is observed LATER than a fault.
Fault may be the cause for a Failure. Fault is "WHAT" and Failure is "WHEN".
Those are only fundamentals, but still I hope that it sheds some light on the matter.
For better or worse, Mathematica provides a wealth of constructs that allow you to do non-local transfers of control, including Return, Catch/Throw, Abort and Goto. However, these kinds of non-local transfers of control often conflict with writing robust programs that need to ensure that clean-up code (like closing streams) gets run. Many languages provide ways of ensuring that clean-up code gets run in a wide variety of circumstances; Java has its finally blocks, C++ has destructors, Common Lisp has UNWIND-PROTECT, and so on.
In Mathematica, I don't know how to accomplish the same thing. I have a partial solution that looks like this:
Attributes[CleanUp] = {HoldAll};
CleanUp[body_, form_] :=
Module[{return, aborted = False},
Catch[
CheckAbort[
return = body,
aborted = True];
form;
If[aborted,
Abort[],
return],
_, (form; Throw[##]) &]];
This certainly isn't going to win any beauty contests, but it also only handles Abort and Throw. In particular, it fails in the presence of Return; I figure if you're using Goto to do this kind of non-local control in Mathematica you deserve what you get.
I don't see a good way around this. There's no CheckReturn for instance, and when you get right down to it, Return has pretty murky semantics. Is there a trick I'm missing?
EDIT: The problem with Return, and the vagueness in its definition, has to do with its interaction with conditionals (which somehow aren't "control structures" in Mathematica). An example, using my CleanUp form:
CleanUp[
If[2 == 2,
If[3 == 3,
Return["foo"]]];
Print["bar"],
Print["cleanup"]]
This will return "foo" without printing "cleanup". Likewise,
CleanUp[
baz /.
{bar :> Return["wongle"],
baz :> Return["bongle"]},
Print["cleanup"]]
will return "bongle" without printing cleanup. I don't see a way around this without tedious, error-prone and maybe impossible code-walking or somehow locally redefining Return using Block, which is heinously hacky and doesn't actually seem to work (though experimenting with it is a great way to totally wedge a kernel!)
Great question, but I don't agree that the semantics of Return are murky; They are documented in the link you provide. In short, Return exits the innermost construct (namely, a control structure or function definition) in which it is invoked.
The only case in which your CleanUp function above fails to cleanup from a Return is when you directly pass a single or CompoundExpression (e.g. (one;two;three) directly as input to it.
Return exits the function f:
In[28]:= f[] := Return["ret"]
In[29]:= CleanUp[f[], Print["cleaned"]]
During evaluation of In[29]:= cleaned
Out[29]= "ret"
Return exits x:
In[31]:= x = Return["foo"]
In[32]:= CleanUp[x, Print["cleaned"]]
During evaluation of In[32]:= cleaned
Out[32]= "foo"
Return exits the Do loop:
In[33]:= g[] := (x = 0; Do[x++; Return["blah"], {10}]; x)
In[34]:= CleanUp[g[], Print["cleaned"]]
During evaluation of In[34]:= cleaned
Out[34]= 1
Returns from the body of CleanUp at the point where body is evaluated (since CleanUp is HoldAll):
In[35]:= CleanUp[Return["ret"], Print["cleaned"]];
Out[35]= "ret"
In[36]:= CleanUp[(Print["before"]; Return["ret"]; Print["after"]),
Print["cleaned"]]
During evaluation of In[36]:= before
Out[36]= "ret"
As I noted above, the latter two examples are the only problematic cases I can contrive (although I could be wrong) but they can be handled by adding a definition to CleanUp:
In[44]:= CleanUp[CompoundExpression[before___, Return[ret_], ___], form_] :=
(before; form; ret)
In[45]:= CleanUp[Return["ret"], Print["cleaned"]]
During evaluation of In[46]:= cleaned
Out[45]= "ret"
In[46]:= CleanUp[(Print["before"]; Return["ret"]; Print["after"]),
Print["cleaned"]]
During evaluation of In[46]:= before
During evaluation of In[46]:= cleaned
Out[46]= "ret"
As you said, not going to win any beauty contests, but hopefully this helps solve your problem!
Response to your update
I would argue that using Return inside If is unnecessary, and even an abuse of Return, given that If already returns either the second or third argument based on the state of the condition in the first argument. While I realize your example is probably contrived, If[3==3, Return["Foo"]] is functionally identical to If[3==3, "foo"]
If you have a more complicated If statement, you're better off using Throw and Catch to break out of the evaluation and "return" something to the point you want it to be returned to.
That said, I realize you might not always have control over the code you have to clean up after, so you could always wrap the expression in CleanUp in a no-op control structure, such as:
ret1 = Do[ret2 = expr, {1}]
... by abusing Do to force a Return not contained within a control structure in expr to return out of the Do loop. The only tricky part (I think, not having tried this) is having to deal with two different return values above: ret1 will contain the value of an uncontained Return, but ret2 would have the value of any other evaluation of expr. There's probably a cleaner way to handle that, but I can't see it right now.
HTH!
Pillsy's later version of CleanUp is a good one. At the risk of being pedantic, I must point out a troublesome use case:
Catch[CleanUp[Throw[23], Print["cleanup"]]]
The problem is due to the fact that one cannot explicitly specify a tag pattern for Catch that will match an untagged Throw.
The following version of CleanUp addresses that problem:
SetAttributes[CleanUp, HoldAll]
CleanUp[expr_, cleanup_] :=
Module[{exprFn, result, abort = False, rethrow = True, seq},
exprFn[] := expr;
result = CheckAbort[
Catch[
Catch[result = exprFn[]; rethrow = False; result],
_,
seq[##]&
],
abort = True
];
cleanup;
If[abort, Abort[]];
If[rethrow, Throw[result /. seq -> Sequence]];
result
]
Alas, this code is even less likely to be competitive in a beauty contest. Furthermore, it wouldn't surprise me if someone jumped in with yet another non-local control flow that that this code will not handle. Even in the unlikely event that it handles all possible cases now, problematic cases could be introduced in Mathematica X (where X > 7.01).
I fear that there cannot be a definitive answer to this problem until Wolfram introduces a new control structure expressly for this purpose. UnwindProtect would be a fine name for such a facility.
Michael Pilat provided the key trick for "catching" returns, but I ended up using it in a slightly different way, using the fact that Return forces the return value of a named function as well as control structures like Do. I made the expression that is being cleaned up after into the down-value of a local symbol, like so:
Attributes[CleanUp] = {HoldAll};
CleanUp[expr_, form_] :=
Module[{body, value, aborted = False},
body[] := expr;
Catch[
CheckAbort[
value = body[],
aborted = True];
form;
If[aborted,
Abort[],
value],
_, (form; Throw[##]) &]];