Is there a trick in sing the UNDO, THROW statement? It seems to be a hit or miss. I have already added "ROUTINE-LEVEL ON ERROR UNDO, THROW" to my CLS files but still the UNDO, THROW will just hang the application instead of displaying the standard .NET messagebox for unhandled exception.
I'm out of the office until Tuesday May 22nd but will respond to your message as soon as possible on my return.
If you have an urgent issue in the meantime please contact our Support team using support@bordermerchantsystems.co.uk , or the contact numbers below.
Kind regards
Gareth Edwards
Border Merchant Systems
www.bordermerchantsystems.co.uk
Merchant House
Whitecross Street
Monmouth
NP25 3BY
Tel: 01600 715139
Fax: 01600 716971
The information contained in this e-mail is confidential and privileged; if you are not the intended recipient please notify the sender and delete the message.
Any views or opinions presented are solely those of the author.
not that I play with the .Net gui too much but afraid there is no default 'unhandled exception' message but the default ABL error handling, in that case the error/exception is probably finally catch in an "undo, retry" block which put the whole thing in an endless loop.
We don't use UNDO, RETRY.
The purpose of UNDO THROW, is to do the undo and then pass control up along with the error up to the caller. The caller needs to handle the error - in your case display the error. It is like putting NO-ERROR on the statement in that is stops any system processing of the error. If you do not want to handle the error yourself, remove the THROW and you should see the error message pop up automatically.
-Shelley
I'm not so sure I understand what you mean by remove THROW to display the message automatically.
Basically, I just want to stop the program execution if I THROW an exception (mostly custom exceptions), if it's not handled, the unhandled exception message box should show.
jquerijero wrote:
I'm not so sure I understand what you mean by remove THROW to display the message automatically.
Basically, I just want to stop the program execution if I THROW an exception (mostly custom exceptions), if it's not handled, the unhandled exception message box should show.
So there is some interesting behaviour here (I tested in OE11 but seem to remember this being the same in 10.2B). Run the attached Form1 for example, using the code below.
def var oForm as Form1.
oForm = new Form1().
wait-for System.Windows.Forms.Application:Run(oForm).
catch oError as Progress.Lang.Error :
message
' after wait-for'
oError:GetMessage(1)
view-as alert-box.
end catch.
There are4 buttons on the form, corresponding to 4 states: caught and uncaught, and P.L.Error and P.L.AppError. Each button has their own event handler. The uncaught buttons simply raise error and let the form deal with them (it uses ROUTINE-LEVEL); the caught buttons have a CATCH statement, in which they message the error. They also UNDO, THROW the caught error.
The difference in behaviour comes when the errors have 'real' error messages (ie numbered, not simply using ReturnValue). I call those 'error' and the others 'apperror'. The 'apperror' messages are simply swallowed by either the AVM or the CLR or something inbetween. The 'error' errors raise a message, but this cannot be caught anywhere. That CATCH after the WAIT-FOR does nothing.
The text below comes from the GUI for .NET Programming guide, in the OE11 doc set (~pg98). Because of this I have a standard to have a catch in all my event handlers, so that I can intercept the errors before they get handed off to .NET and disappear into the gloom default display device
Raising errors from ABL handlers for .NET events
When a .NET event is published to which you have subscribed ABL handlers (see the
“Handling .NET events” section on page 82), if an error condition is raised from an ABL
handler for the .NET event, the AVM does not throw an Exception to the .NET
Common Language Runtime (CLR), but displays a message to the default output
device and processing continues as if no error has occurred. Thus, if any handlers for
the event have not yet run when a handler raises an error, all remaining handlers
continue to run.
Edit: I should note that the OE11 doc is vastly better than the 10.2A doc in this regard.
[View:~/cfs-file.ashx/__key/communityserver-discussions-components-files/19/2313.Form1.cls.zip:550:0]
HTH at least a little,
-- peter
So the trick is, if using AppError, to supply a number?
So the trick is, if using AppError, to supply a number?
Yes. That's a huge design failure with the AppError constructors: The usage of the optional second integer parameter changes the meaning of the first character parameter...
I guess every ABL developer dealing with the structured error handling must have gone through that experience once or twice ...
We typically always use ,0 for the optional numeric parameter.
Also syntax wise, which should we use?
ERROR new Progress.Lang.AppError('Whoops!', 1).
or
UNDO, THROW new Progress.Lang.AppError('Whoops!', 1).
What is the difference by the way?
seconded. Always use a number at the end, even if it's 0
Looks like the actual message string and number of messages are not being passed to the CATCH if using AppError with no second parameter. This seems like a bug.
This seems like a bug.
The bug wqas the spec, not the implementation
NEW AppError ("Hello World") .
--> AppError with NO message but a ReturnValue set, equally to RETURN ERROR "Hello World" .
NEW AppError ("Hello World", 0) .
--> AppError with one message and NO ReturnValue set.
What is the difference by the way?
I assume in the first case, that was the RETURN ERROR Syntax. Right?
UNDO, THROW throws to the next block.
RETURN ERROR throws to the caller of the current routine.
Not so sure why AppError is muddied up this way if RETURN ERROR "some string" is still functional.
Not so sure why AppError is muddied up this way if RETURN ERROR "some
string" is still functional.
I suspect for backwards compatibility reasons. Take the following code.
Called.p
RETURN ERROR "ABC".
Caller.p
RUN called.p NO-ERROR.
IF RETURN-VALUE <> "" THEN /* handle */.
If called.p now implements something like the following anywhere
UNDO, THROW NEW AppError("ABC")
Caller.p doesn't have to change.
-- peter
Does this mean RETURN ERROR will be deprecated in the future?
Does this mean RETURN ERROR will be deprecated in the future?
I wouldn't see a need for that.
And for as long as Progress has to support ADM and ADM2 that would cause them a lot of trouble themselves. ADM's are built around RETURN ERROR "ADM-ERROR".
I guess RETURN ERROR AppError("string") is fine, but the behavior just feels very inconsistent for the THROW statement.
jmls wrote:
seconded. Always use a number at the end, even if it's 0
Mike, Julian,
So it seems the difference is that one AppError() raises the error status, and one doesn't.If I am throwing errors up (via ROUTINE-LEVEL or CATCH and UNDO, THROW or similar), both error objects behave correctly, right? Are you mainly concerned with cases where there are no structured error handling constructs?
-- peter
there's quite a discussion on the issue here
http://communities.progress.com/pcom/message/134220#134220
I remember that discussion. But I'm still not clear on exactly what problem it causes: I realise that the error status is raised only sometimes, but if you're catching/handling errors, how does this impact you? There's probably something really simple I'm not getting here. Please use short words and lots of patience
-- peter
The biggest issue is consistency.
- Inside the CATCH, unless you have all programmers coding the same way, you will have to check GetNumMessages if greater than zero else check error status to handle both constructor definitions.
- As for the THROW statement, to me, THROW really means throw an exception error.
Got it.
Thanks,
-- peter
jquerijero wrote:
The biggest issue is consistency.
- Inside the CATCH, unless you have all programmers coding the same way, you will have to check GetNumMessages if greater than zero else check error status to handle both constructor definitions.
- As for the THROW statement, to me, THROW really means throw an exception error.
So back in the pre-AppError days, we also had to do the double check:
RUN foo.p NO-ERROR.
IF RETURN-VALUE <> "" OR ERROR-STATUS:ERROR THEN
DO:
IF RETURN-VALUE <> "" THEN ...
ELSE
DO i = 1 TO ERROR-STATUS:NUM-MESSAGES:
...
END.
The current approach is consistent with that way of coding error handling. Not to say that this is ideal, just that it's backward compatible in a sense. A better OO approach might be to have a separate type for ReturnValue 'errors'. Or would you suggest something else? Which style do you use more - the single value/return value, or the one or more numbered messages approach?
-- peter
bzzt.
/*************/
foo.p: (#1)
return error "this is an error".
or
foo.p (#2)
return "this is ok".
/***********/
IF RETURN-VALUE <> "" OR ERROR-STATUS:ERROR THEN
would trap both #1 and #2 of foo.p , although #2 is not an error
Our priority when we introduced structured error handling was cross compatibility with the existing and the new. Maybe we went a little too far.
But this is the beauty of OO. You can create a subclass of AppError that you use in your coding that has a constructor that takes a single message string and inside that constructor, call the AppError constructor with (message-string, 1). Then you never have to deal with it again!
Thanks
-Shelley
RETURN-VALUE is not always an error like what Julian pointed out.
You *could* also go a step further ...
using Progress.Lang.*.
using Progress.Lang.AppError.
class AppError inherits AppError:
constructor AppError(p_message as char,p_ErrorNum as int):
super(p_message,p_ErrorNum).
end constructor .
constructor AppError(p_message as char):
super(p_message,0).
end constructor .
end class.
That is fine. My experience aside from consistency though is that the application can also hang when the AppError with only one parameter is used, and there is no CATCH block. It's hard to debug when this happens. In this case, I would rather deal with unhandled exception error.
Since RETURN ERROR is not being deprecated, I think it would have been a lot clearer if it stays as a separate functionality from AppError. I mean, I would have rather learn a new statement something like RETURN THROW for the the new functionality.
backward compatibility should be enough, cross compatibility might be a
bit too much
nevertheless, sub-classing AppError is something that we should do
anyway (the different constructors behaviour is something some of us
have learned the hard way)... having AppError as an abstract class (or
maybe just an interface) could have been helpful in that regard
anyone considering using the structured error handling might start by
defining different kind of exceptions/errors, those can be trapped in
separate catch blocks in case handling need to be different from one
error to another... having a 'catch all' block does not make much sense,
it's like you don't need error handling at all and let the run-time to
spit default errors when it 'trap' those.
one day maybe (wishful thinking) we might be able to specify the kind of
exceptions/errors a method can throw, having only AppError as an
alternative does not tell much
--
m.edu
keep it simple
www.ganimede.ro
medu@ganimede.ro
But this is the beauty of OO. You can create a subclass of AppError that you use in your coding that has a constructor that takes a single message string and inside that constructor, call the AppError constructor with (message-string, 1). Then you never have to deal with it again!
If just all OpenEdge customers would have the habit of extending the built in objects already...
You could also go a step further ...
Don't you think it's the best way to shoot yourself in both feet at once to call the wrapped class the same as the wrapper?
No, I don't. That's why I still have both my feet attached
Is it possible to make the THROW statement behave like the throw statement in Visual Studio where it stops the program execution when an unhandled exception is encountered?
Is it possible to make the THROW statement behave like the throw statement
in Visual Studio where it stops the program execution when an unhandled
exception is encountered?
The Debugger can do this, if that's what you're looking for. There's an option on the 'Add breakpoint' to stop execution at a line or on error or on a watchpoint.
-- peter
I'm thinking of even during run-time. Unhandled exception thrown from pure .NET object stops the program execution but custom error thrown from ABL doesn't. It's just a little inconsistent.