Problem calling error handler from BEGIN...END SEQUENCE
https://www.xsharp.eu/forum/topic?p=32646#p32646
Following code prints in X#:
before BEGIN SEQUENCE .F.
in BEGIN SEQUENCE .T.
in RECOVER .F.
after END SEQUENCE .F.
so the ErrorHandler() function is not called at all, as it does in VO:
before BEGIN SEQUENCE .F.
in BEGIN SEQUENCE .T.
in ErrorHandler .T. // why is this line missing in X#?
in RECOVER .F.
after END SEQUENCE .F.
FUNCTION Start() AS INT
LOCAL oCB AS CODEBLOCK
LOCAL err AS USUAL
oCB := ErrorBlock( {|err| ErrorHandler(err) } )
? "before BEGIN SEQUENCE", CanBreak()
BEGIN SEQUENCE
? "in BEGIN SEQUENCE", CanBreak()
Error{}:Throw()
RECOVER USING err
? "in RECOVER", CanBreak()
END SEQUENCE
ErrorBlock( oCB )
? "after END SEQUENCE", CanBreak()
RETURN 0
FUNCTION ErrorHandler(err) AS USUAL
? "in ErrorHandler", CanBreak()
_Break(err)
? "in ErrorHandler after _break", CanBreak()
RETURN NIL
Some comments: This should have worked as expected when the /vo17 compiler option (VO compatible BEGIN SEQUENCE .. END SEQUENCE) was enabled, but I see now that the code that gets generated is not correctly doing what it is supposed to do.
AFAIK the errorhandler is being called - only CanDefault() is FALSE during its execution and _break() thus doesn't jump to RECOVER but exits the application.
My current workaround ist this:
FUNCTION _SequenceError(e AS Exception) AS USUAL
LOCAL oError AS error
LOCAL uRueck AS USUAL
oError := error{e}
aadd( gaErrorProcLineInfo, getErrorProcLineInfo( oError ) )
uRueck := eval( ErrorBlock(), oError )
asize( gaErrorProcLineInfo, max(0,alen( gaErrorProcLineInfo )-1 ) )
RETURN u
This calls a function retrieving the actual error line (because later in the errorhandler the call stack points to the BEGIN SEQUENCE line in stead of the one which threw the error) and puts it on a stack before moving on to the real error handler. Our own stack handler reads this and makes sure that any stack in protocols which are written during error handling remains useful.
We also have replaced _break() with _ErrorBlockAwareBreak everywhere in our code:
FUNCTION _ErrorBlockAwareBreak( uValue := NIL AS USUAL ) AS VOID
IF CanBreak() .OR. Empty( gaErrorProcLineInfo )
_break( uValue )
ENDIF
RETURN
This makes the code in the called errorblock() running to its end and then jumping back to RECOVER USING. It would also still work once CanBreak() delivers a true value in the future. It's not satisfying, though, because we needed to modify all our errorhandlers because now code after a _break() call would still be executed. IMO all this could be solved if CanBreak() and _break() behave properly.
Stefan, I am aware of this. Unfortunately, this requires a not so easy change in the compiler.
Has there been any progress since then? So far all of our error handling (which is hundreds of begin/sequence loops) still doesn't work in 2.24, causing major trouble. Bug search takes hours and days for every case since applications just shutdown...
Stefan, We have not changed this for X# 2, because a change in this area has a great risk of breaking existing X# code. I promise to look at this for X# 3.