UNDO, THROW statement is hit or miss

Posted by jquerijero on 17-May-2012 16:06

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.

All Replies

Posted by ge1971 on 17-May-2012 16:11

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.

Posted by Admin on 18-May-2012 03:31

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.

Posted by jquerijero on 18-May-2012 09:42

We don't use UNDO, RETRY.

Posted by Shelley Chase on 18-May-2012 12:31

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

Posted by jquerijero on 18-May-2012 13:14

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.

Posted by Peter Judge on 18-May-2012 15:18

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

Posted by jquerijero on 18-May-2012 15:38

So the trick is, if using AppError, to supply a number?

Posted by Admin on 18-May-2012 15:41

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.

Posted by jquerijero on 18-May-2012 15:44

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?

Posted by jmls on 18-May-2012 15:46

seconded. Always use a number at the end, even if it's 0

Posted by jquerijero on 18-May-2012 15:53

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.

Posted by Admin on 18-May-2012 16:01

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.

Posted by Admin on 18-May-2012 16:01

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.

Posted by jquerijero on 18-May-2012 16:11

Not so sure why AppError is muddied up this way if RETURN ERROR "some string" is still functional.

Posted by Peter Judge on 21-May-2012 07:41

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

Posted by jquerijero on 21-May-2012 09:49

Does this mean RETURN ERROR will be deprecated in the future?

Posted by Admin on 21-May-2012 09:56

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".

Posted by jquerijero on 21-May-2012 10:09

I guess RETURN ERROR AppError("string") is fine, but the behavior just feels very inconsistent for the THROW statement.

Posted by Peter Judge on 21-May-2012 10:12

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

Posted by jmls on 21-May-2012 10:41

there's quite a discussion on the issue here

http://communities.progress.com/pcom/message/134220#134220

Posted by Peter Judge on 21-May-2012 10:51

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

Posted by jquerijero on 21-May-2012 11:08

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.

Posted by Peter Judge on 21-May-2012 11:26

Got it.

Thanks,

-- peter

Posted by Peter Judge on 21-May-2012 12:38

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

Posted by jmls on 21-May-2012 12:51

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

Posted by Shelley Chase on 21-May-2012 12:58

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

Posted by jquerijero on 21-May-2012 13:01

RETURN-VALUE is not always an error like what Julian pointed out.

Posted by jmls on 21-May-2012 13:05

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.

Posted by jquerijero on 21-May-2012 13:08

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.

Posted by jquerijero on 21-May-2012 13:12

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.

Posted by Admin on 21-May-2012 13:36

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

Posted by Admin on 21-May-2012 16:21

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...

Posted by Admin on 21-May-2012 16:21

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?

Posted by jmls on 22-May-2012 00:31

No, I don't. That's why I still have both my feet attached

Posted by jquerijero on 22-May-2012 09:43

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?

Posted by Peter Judge on 22-May-2012 09:51

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

Posted by jquerijero on 22-May-2012 09:55

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.

This thread is closed