Simple Error Handling

Posted by Thomas Mercer-Hursh on 20-May-2015 16:28

I keep learning more about error handling ... by discovering things that I didn't know. 

I started out my current project with catch blocks for AppError and SysError.  The former logging ReturnValue and the latter logging GetMessages and the CallStack.  Then, because of .NET errors from Proparse, it was suggested that I add a catch block for just Error which also included GetMessages and CallStack.  This seemed to help.

But, now some new questions.

Having gone back to the manual because of some issues, I see that Error is an interface, not a superclass.  So, I'm wondering if my third catch block above shouldn't be for ProError instead.  Would it make any difference?

I am currently doing some little batch utilities which don't have all the logging of the main project.  So, I thought I would just put in a simple catch block for Error and dump the GetMessages and CallStack to the output file in the unlikely event that something went wrong.  But, I find that GetMessages doesn't give one the ReturnValue if I throw an AppError.  So, does this mean that I need at least two catch blocks for AppError and Error (or ProError)?  Or do I actually need all three?

All Replies

Posted by Peter Judge on 20-May-2015 19:18

Catching Error and AppError will catch everything. The only reason for AppError is for the ReturnValue , and for that you can work around it (by adding a message number).
 
Since AppError implements Error, a catch Error block will catch those too, but I prefer not to have case statements on type in catch blocks.
 
-- peter
 
[collapse]
From: Thomas Mercer-Hursh [mailto:bounce-tamhas@community.progress.com]
Sent: Wednesday, 20 May, 2015 17:30
To: TU.OE.Development@community.progress.com
Subject: [Technical Users - OE Development] Simple Error Handling
 
Thread created by Thomas Mercer-Hursh

I keep learning more about error handling ... by discovering things that I didn't know. 

I started out my current project with catch blocks for AppError and SysError.  The former logging ReturnValue and the latter logging GetMessages and the CallStack.  Then, because of .NET errors from Proparse, it was suggested that I add a catch block for just Error which also included GetMessages and CallStack.  This seemed to help.

But, now some new questions.

Having gone back to the manual because of some issues, I see that Error is an interface, not a superclass.  So, I'm wondering if my third catch block above shouldn't be for ProError instead.  Would it make any difference?

I am currently doing some little batch utilities which don't have all the logging of the main project.  So, I thought I would just put in a simple catch block for Error and dump the GetMessages and CallStack to the output file in the unlikely event that something went wrong.  But, I find that GetMessages doesn't give one the ReturnValue if I throw an AppError.  So, does this mean that I need at least two catch blocks for AppError and Error (or ProError)?  Or do I actually need all three?

Stop receiving emails on this subject.

Flag this post as spam/abuse.

[/collapse]

Posted by Laura Stern on 20-May-2015 19:22

I have to apologize that after all this error handling banter I really don't know what the issue is.

As someone (Peter Judge?) had answered in the prior conversation (that I can't see here) you should make sure there is an error message in your AppErrors by passing 2 parameters to the constructor (message and #) or using the AddMessage method.  Then you can always get the message with GetMessage. Why would you care about ReturnValue?  That is only really there for backward compatibility with non-structured error handling.  

The Error interface will work for all error types, including .NET exceptions.  You can have a single catch block or more than one.  If you only have one you can always test the type of the actual error object you got if you need to get extra information from that specific type - like ReturnValue if you still want to use that.  You can have both a ReturnValue and an error message in the same AppError.  

So what's the question/problem?

Posted by Jeff Ledbetter on 20-May-2015 19:29

“..but I prefer not to have case statements on type in catch blocks.”
 
Why? What if it does the job?
 
Sometimes it helps integrate older and new code..
 
  CATCH e AS Progress.Lang.Error:
   
    IF TYPE-OF(e,AppError) THEN
      pcError = CAST(e,AppError):returnValue.
 
    IF TYPE-OF(e,SysError) THEN
      pcError = DYNAMIC-FUNCTION('fnRtbErrorHandlerObject', CAST(e,SysError)).
     
  END CATCH.
 
Jeff Ledbetter
skype: jeff.ledbetter
 
[collapse]
From: Peter Judge [mailto:bounce-pjudge@community.progress.com]
Sent: Wednesday, May 20, 2015 7:20 PM
To: TU.OE.Development@community.progress.com
Subject: RE: [Technical Users - OE Development] Simple Error Handling
 
Reply by Peter Judge
Catching Error and AppError will catch everything. The only reason for AppError is for the ReturnValue , and for that you can work around it (by adding a message number).
 
Since AppError implements Error, a catch Error block will catch those too, but I prefer not to have case statements on type in catch blocks.
 
-- peter
 
[collapse]
From: Thomas Mercer-Hursh [mailto:bounce-tamhas@community.progress.com]
Sent: Wednesday, 20 May, 2015 17:30
To: TU.OE.Development@community.progress.com
Subject: [Technical Users - OE Development] Simple Error Handling
 
Thread created by Thomas Mercer-Hursh

I keep learning more about error handling ... by discovering things that I didn't know. 

I started out my current project with catch blocks for AppError and SysError.  The former logging ReturnValue and the latter logging GetMessages and the CallStack.  Then, because of .NET errors from Proparse, it was suggested that I add a catch block for just Error which also included GetMessages and CallStack.  This seemed to help.

But, now some new questions.

Having gone back to the manual because of some issues, I see that Error is an interface, not a superclass.  So, I'm wondering if my third catch block above shouldn't be for ProError instead.  Would it make any difference?

I am currently doing some little batch utilities which don't have all the logging of the main project.  So, I thought I would just put in a simple catch block for Error and dump the GetMessages and CallStack to the output file in the unlikely event that something went wrong.  But, I find that GetMessages doesn't give one the ReturnValue if I throw an AppError.  So, does this mean that I need at least two catch blocks for AppError and Error (or ProError)?  Or do I actually need all three?

Stop receiving emails on this subject.

Flag this post as spam/abuse.

Stop receiving emails on this subject.

Flag this post as spam/abuse.

[/collapse][/collapse]

Posted by Peter Judge on 20-May-2015 19:51

It's a preference :) Both work equally well.
 
Catch eAE as AppError:
  pcError = eAE:returnVAlue.
End catch.
 
Catch eSE as SysError:
  pcError = {fnarg fnRtbErrorHandlerObject eSE}.
End catch.
 
Catch eE as Error:
 Do iLoop =  1 to eE:NumMessages:
    pcError = pcError + cDelimter + e:GetMessage(iLoop) .
  end.
end catch.
 
This works better for me (but again, as Brian said, we're all individuals).
 
-- peter
 
 
[collapse]
From: Jeff Ledbetter [mailto:bounce-jeffledbetter@community.progress.com]
Sent: Wednesday, 20 May, 2015 20:30
To: TU.OE.Development@community.progress.com
Subject: RE: [Technical Users - OE Development] Simple Error Handling
 
Reply by Jeff Ledbetter
“..but I prefer not to have case statements on type in catch blocks.”
 
Why? What if it does the job?
 
Sometimes it helps integrate older and new code..
 
  CATCH e AS Progress.Lang.Error:
   
    IF TYPE-OF(e,AppError) THEN
      pcError = CAST(e,AppError):returnValue.
 
    IF TYPE-OF(e,SysError) THEN
      pcError = DYNAMIC-FUNCTION('fnRtbErrorHandlerObject', CAST(e,SysError)).
     
  END CATCH.
 
Jeff Ledbetter
skype: jeff.ledbetter
 
[collapse]
From: Peter Judge [mailto:bounce-pjudge@community.progress.com]
Sent: Wednesday, May 20, 2015 7:20 PM
To: TU.OE.Development@community.progress.com
Subject: RE: [Technical Users - OE Development] Simple Error Handling
 
Reply by Peter Judge
Catching Error and AppError will catch everything. The only reason for AppError is for the ReturnValue , and for that you can work around it (by adding a message number).
 
Since AppError implements Error, a catch Error block will catch those too, but I prefer not to have case statements on type in catch blocks.
 
-- peter
 
[collapse]
From: Thomas Mercer-Hursh [mailto:bounce-tamhas@community.progress.com]
Sent: Wednesday, 20 May, 2015 17:30
To: TU.OE.Development@community.progress.com
Subject: [Technical Users - OE Development] Simple Error Handling
 
Thread created by Thomas Mercer-Hursh

I keep learning more about error handling ... by discovering things that I didn't know. 

I started out my current project with catch blocks for AppError and SysError.  The former logging ReturnValue and the latter logging GetMessages and the CallStack.  Then, because of .NET errors from Proparse, it was suggested that I add a catch block for just Error which also included GetMessages and CallStack.  This seemed to help.

But, now some new questions.

Having gone back to the manual because of some issues, I see that Error is an interface, not a superclass.  So, I'm wondering if my third catch block above shouldn't be for ProError instead.  Would it make any difference?

I am currently doing some little batch utilities which don't have all the logging of the main project.  So, I thought I would just put in a simple catch block for Error and dump the GetMessages and CallStack to the output file in the unlikely event that something went wrong.  But, I find that GetMessages doesn't give one the ReturnValue if I throw an AppError.  So, does this mean that I need at least two catch blocks for AppError and Error (or ProError)?  Or do I actually need all three?

Stop receiving emails on this subject.

Flag this post as spam/abuse.

Stop receiving emails on this subject.

Flag this post as spam/abuse.

Stop receiving emails on this subject.

Flag this post as spam/abuse.

[/collapse][/collapse][/collapse]

Posted by Jeff Ledbetter on 20-May-2015 20:04

Oh, ok. Same thing but different technique. I thought you meant you were against the catching of different types. Although that wouldn’t make sense now would it.  I should step away now..
 
Jeff Ledbetter
skype: jeff.ledbetter
 
[collapse]
From: Peter Judge [mailto:bounce-pjudge@community.progress.com]
Sent: Wednesday, May 20, 2015 7:52 PM
To: TU.OE.Development@community.progress.com
Subject: RE: [Technical Users - OE Development] Simple Error Handling
 
Reply by Peter Judge
It's a preference :) Both work equally well.
 
Catch eAE as AppError:
  pcError = eAE:returnVAlue.
End catch.
 
Catch eSE as SysError:
  pcError = {fnarg fnRtbErrorHandlerObject eSE}.
End catch.
 
Catch eE as Error:
 Do iLoop =  1 to eE:NumMessages:
    pcError = pcError + cDelimter + e:GetMessage(iLoop) .
  end.
end catch.
 
This works better for me (but again, as Brian said, we're all individuals).
 
-- peter
 
 
[collapse]
From: Jeff Ledbetter [mailto:bounce-jeffledbetter@community.progress.com]
Sent: Wednesday, 20 May, 2015 20:30
To: TU.OE.Development@community.progress.com
Subject: RE: [Technical Users - OE Development] Simple Error Handling
 
Reply by Jeff Ledbetter
“..but I prefer not to have case statements on type in catch blocks.”
 
Why? What if it does the job?
 
Sometimes it helps integrate older and new code..
 
  CATCH e AS Progress.Lang.Error:
   
    IF TYPE-OF(e,AppError) THEN
      pcError = CAST(e,AppError):returnValue.
 
    IF TYPE-OF(e,SysError) THEN
      pcError = DYNAMIC-FUNCTION('fnRtbErrorHandlerObject', CAST(e,SysError)).
     
  END CATCH.
 
Jeff Ledbetter
skype: jeff.ledbetter
 
[collapse]
From: Peter Judge [mailto:bounce-pjudge@community.progress.com]
Sent: Wednesday, May 20, 2015 7:20 PM
To: TU.OE.Development@community.progress.com
Subject: RE: [Technical Users - OE Development] Simple Error Handling
 
Reply by Peter Judge
Catching Error and AppError will catch everything. The only reason for AppError is for the ReturnValue , and for that you can work around it (by adding a message number).
 
Since AppError implements Error, a catch Error block will catch those too, but I prefer not to have case statements on type in catch blocks.
 
-- peter
 
[collapse]
From: Thomas Mercer-Hursh [mailto:bounce-tamhas@community.progress.com]
Sent: Wednesday, 20 May, 2015 17:30
To: TU.OE.Development@community.progress.com
Subject: [Technical Users - OE Development] Simple Error Handling
 
Thread created by Thomas Mercer-Hursh

I keep learning more about error handling ... by discovering things that I didn't know. 

I started out my current project with catch blocks for AppError and SysError.  The former logging ReturnValue and the latter logging GetMessages and the CallStack.  Then, because of .NET errors from Proparse, it was suggested that I add a catch block for just Error which also included GetMessages and CallStack.  This seemed to help.

But, now some new questions.

Having gone back to the manual because of some issues, I see that Error is an interface, not a superclass.  So, I'm wondering if my third catch block above shouldn't be for ProError instead.  Would it make any difference?

I am currently doing some little batch utilities which don't have all the logging of the main project.  So, I thought I would just put in a simple catch block for Error and dump the GetMessages and CallStack to the output file in the unlikely event that something went wrong.  But, I find that GetMessages doesn't give one the ReturnValue if I throw an AppError.  So, does this mean that I need at least two catch blocks for AppError and Error (or ProError)?  Or do I actually need all three?

Stop receiving emails on this subject.

Flag this post as spam/abuse.

Stop receiving emails on this subject.

Flag this post as spam/abuse.

Stop receiving emails on this subject.

Flag this post as spam/abuse.

Stop receiving emails on this subject.

Flag this post as spam/abuse.

[/collapse][/collapse][/collapse][/collapse]

Posted by Thomas Mercer-Hursh on 20-May-2015 20:22

Are you saying that if I include an error number in addition to the message when throwing an AppError, that it will show up in GetMessages?  I thought I tried that and did *not* get anything.

Posted by Laura Stern on 20-May-2015 20:40

Correct. There are two different AppError constructors, one that just takes a message (which sets ReturnValue) and the other that takes a message and a # (don't remember in which order).  This sets an error message and a message #.  And regardless of which constructor you use, you can always add a message or set a ReturnValue by using the other methods and properties of AppError.  

Posted by Mike Fechner on 20-May-2015 23:41

Dr. Hursh, I strongly recommend attending my session on structured error handling at a PUG Challenge near you this year. :-)

It should answer all your questions....

Von meinem Windows Phone gesendet

Von: Thomas Mercer-Hursh
Gesendet: ‎21.‎05.‎2015 03:23
An: TU.OE.Development@community.progress.com
Betreff: RE: [Technical Users - OE Development] Simple Error Handling

Reply by Thomas Mercer-Hursh

Are you saying that if I include an error number in addition to the message when throwing an AppError, that it will show up in GetMessages?  I thought I tried that and did *not* get anything.

Stop receiving emails on this subject.

Flag this post as spam/abuse.

Posted by Mike Fechner on 20-May-2015 23:46

Must say I share Peters preference here.

Plus the individual catch blocks on AppError and SysError would allow you to on purpose not catch Exceptions and SoapErrors.

Using a Single catch for Error with the CASE you will have to re-throw error you can't handle there.

This is even more true when you start adding custom error types (Childs or grand Childs or grand grand Childs of AppError) and need different handling in different locations for custom errors like NotAuthorizedException vs. assertException vs. NotSupportedOnMondayException.

Von meinem Windows Phone gesendet

Von: Peter Judge
Gesendet: ‎21.‎05.‎2015 02:52
An: TU.OE.Development@community.progress.com
Betreff: RE: [Technical Users - OE Development] Simple Error Handling

Reply by Peter Judge
It's a preference :) Both work equally well.
 
Catch eAE as AppError:
  pcError = eAE:returnVAlue.
End catch.
 
Catch eSE as SysError:
  pcError = {fnarg fnRtbErrorHandlerObject eSE}.
End catch.
 
Catch eE as Error:
 Do iLoop =  1 to eE:NumMessages:
    pcError = pcError + cDelimter + e:GetMessage(iLoop) .
  end.
end catch.
 
This works better for me (but again, as Brian said, we're all individuals).
 
-- peter
 
 
[collapse]
From: Jeff Ledbetter [mailto:bounce-jeffledbetter@community.progress.com]
Sent: Wednesday, 20 May, 2015 20:30
To: TU.OE.Development@community.progress.com
Subject: RE: [Technical Users - OE Development] Simple Error Handling
 
Reply by Jeff Ledbetter
“..but I prefer not to have case statements on type in catch blocks.”
 
Why? What if it does the job?
 
Sometimes it helps integrate older and new code..
 
  CATCH e AS Progress.Lang.Error:
   
    IF TYPE-OF(e,AppError) THEN
      pcError = CAST(e,AppError):returnValue.
 
    IF TYPE-OF(e,SysError) THEN
      pcError = DYNAMIC-FUNCTION('fnRtbErrorHandlerObject', CAST(e,SysError)).
     
  END CATCH.
 
Jeff Ledbetter
skype: jeff.ledbetter
 
[collapse]
From: Peter Judge [mailto:bounce-pjudge@community.progress.com]
Sent: Wednesday, May 20, 2015 7:20 PM
To: TU.OE.Development@community.progress.com
Subject: RE: [Technical Users - OE Development] Simple Error Handling
 
Reply by Peter Judge
Catching Error and AppError will catch everything. The only reason for AppError is for the ReturnValue , and for that you can work around it (by adding a message number).
 
Since AppError implements Error, a catch Error block will catch those too, but I prefer not to have case statements on type in catch blocks.
 
-- peter
 
[collapse]
From: Thomas Mercer-Hursh [mailto:bounce-tamhas@community.progress.com]
Sent: Wednesday, 20 May, 2015 17:30
To: TU.OE.Development@community.progress.com
Subject: [Technical Users - OE Development] Simple Error Handling
 
Thread created by Thomas Mercer-Hursh

I keep learning more about error handling ... by discovering things that I didn't know. 

I started out my current project with catch blocks for AppError and SysError.  The former logging ReturnValue and the latter logging GetMessages and the CallStack.  Then, because of .NET errors from Proparse, it was suggested that I add a catch block for just Error which also included GetMessages and CallStack.  This seemed to help.

But, now some new questions.

Having gone back to the manual because of some issues, I see that Error is an interface, not a superclass.  So, I'm wondering if my third catch block above shouldn't be for ProError instead.  Would it make any difference?

I am currently doing some little batch utilities which don't have all the logging of the main project.  So, I thought I would just put in a simple catch block for Error and dump the GetMessages and CallStack to the output file in the unlikely event that something went wrong.  But, I find that GetMessages doesn't give one the ReturnValue if I throw an AppError.  So, does this mean that I need at least two catch blocks for AppError and Error (or ProError)?  Or do I actually need all three?

Stop receiving emails on this subject.

Flag this post as spam/abuse.

Stop receiving emails on this subject.

Flag this post as spam/abuse.

Stop receiving emails on this subject.

Flag this post as spam/abuse.

Stop receiving emails on this subject.

Flag this post as spam/abuse.

[/collapse][/collapse][/collapse]

Posted by Tim Kuehn on 20-May-2015 23:53

NotSupportedOnMondayException?
Send it to the Coffee routine...

[collapse]
On Thu, May 21, 2015 at 12:47 AM, Mike Fechner <bounce-mikefechner@community.progress.com> wrote:
Reply by Mike Fechner
Must say I share Peters preference here.

Plus the individual catch blocks on AppError and SysError would allow you to on purpose not catch Exceptions and SoapErrors.

Using a Single catch for Error with the CASE you will have to re-throw error you can't handle there.

This is even more true when you start adding custom error types (Childs or grand Childs or grand grand Childs of AppError) and need different handling in different locations for custom errors like NotAuthorizedException vs. assertException vs. NotSupportedOnMondayException.

Von meinem Windows Phone gesendet

Von: Peter Judge
Gesendet: ‎21.‎05.‎2015 02:52
An: TU.OE.Development@community.progress.com
Betreff: RE: [Technical Users - OE Development] Simple Error Handling

Reply by Peter Judge
It's a preference :) Both work equally well.
 
Catch eAE as AppError:
  pcError = eAE:returnVAlue.
End catch.
 
Catch eSE as SysError:
  pcError = {fnarg fnRtbErrorHandlerObject eSE}.
End catch.
 
Catch eE as Error:
 Do iLoop =  1 to eE:NumMessages:
    pcError = pcError + cDelimter + e:GetMessage(iLoop) .
  end.
end catch.
 
This works better for me (but again, as Brian said, we're all individuals).
 
-- peter
 
 
[collapse]
From: Jeff Ledbetter [mailto:bounce-jeffledbetter@community.progress.com]
Sent: Wednesday, 20 May, 2015 20:30
To: TU.OE.Development@community.progress.com
Subject: RE: [Technical Users - OE Development] Simple Error Handling
 
Reply by Jeff Ledbetter
“..but I prefer not to have case statements on type in catch blocks.”
 
Why? What if it does the job?
 
Sometimes it helps integrate older and new code..
 
  CATCH e AS Progress.Lang.Error:
   
    IF TYPE-OF(e,AppError) THEN
      pcError = CAST(e,AppError):returnValue.
 
    IF TYPE-OF(e,SysError) THEN
      pcError = DYNAMIC-FUNCTION('fnRtbErrorHandlerObject', CAST(e,SysError)).
     
  END CATCH.
 
Jeff Ledbetter
skype: jeff.ledbetter
 
[collapse]
From: Peter Judge [mailto:bounce-pjudge@community.progress.com]
Sent: Wednesday, May 20, 2015 7:20 PM
To: TU.OE.Development@community.progress.com
Subject: RE: [Technical Users - OE Development] Simple Error Handling
 
Reply by Peter Judge
Catching Error and AppError will catch everything. The only reason for AppError is for the ReturnValue , and for that you can work around it (by adding a message number).
 
Since AppError implements Error, a catch Error block will catch those too, but I prefer not to have case statements on type in catch blocks.
 
-- peter
 
[collapse]
From: Thomas Mercer-Hursh [mailto:bounce-tamhas@community.progress.com]
Sent: Wednesday, 20 May, 2015 17:30
To: TU.OE.Development@community.progress.com
Subject: [Technical Users - OE Development] Simple Error Handling
 
Thread created by Thomas Mercer-Hursh

I keep learning more about error handling ... by discovering things that I didn't know. 

I started out my current project with catch blocks for AppError and SysError.  The former logging ReturnValue and the latter logging GetMessages and the CallStack.  Then, because of .NET errors from Proparse, it was suggested that I add a catch block for just Error which also included GetMessages and CallStack.  This seemed to help.

But, now some new questions.

Having gone back to the manual because of some issues, I see that Error is an interface, not a superclass.  So, I'm wondering if my third catch block above shouldn't be for ProError instead.  Would it make any difference?

I am currently doing some little batch utilities which don't have all the logging of the main project.  So, I thought I would just put in a simple catch block for Error and dump the GetMessages and CallStack to the output file in the unlikely event that something went wrong.  But, I find that GetMessages doesn't give one the ReturnValue if I throw an AppError.  So, does this mean that I need at least two catch blocks for AppError and Error (or ProError)?  Or do I actually need all three?

Stop receiving emails on this subject.

Flag this post as spam/abuse.

Stop receiving emails on this subject.

Flag this post as spam/abuse.

Stop receiving emails on this subject.

Flag this post as spam/abuse.

Stop receiving emails on this subject.

Flag this post as spam/abuse.

Stop receiving emails on this subject.

Flag this post as spam/abuse.



--
Tim Kuehn:  Senior Consultant  - TDK Consulting Services
President - Ontario PUG 
Program Committee Chair - PUG Challenge Americas, 
Course Instructor: Intro to OO Concepts for Procedural Programmers

Skype: timothy.kuehn
Ph: 519-576-8100
Cell: 519-781-0081
[/collapse][/collapse][/collapse][/collapse]

Posted by Simon L. Prinsloo on 21-May-2015 02:06

To answer the original question:

ProError is the super class for AppError and SysError, but not for other errors, e.g. .Net errors.

But all errors implements the Error interface.

So you can catch the AppError and use its ReturnValue and/or any messages it contains, followed by catching the Error interface to catch anything else that is left.

Alternatively you can catch the Error interface only. If it has no messages, you can test if it is an AppError and if so, cast it and check for a ReturnValue.

I do not quite comprehend why the two AppError contructors cause you to always end up without a message somewhere, as it always complicates things and leads to unnatural code, e.g. "NEW AppError('My messages', any0meaningless-integer)" just to get the "new" structured error handling to work.

For compatibility with traditional errors, I would expect that the ReturnValue property's getter should simply map to GetMessage(1) and that it would either be a) ReadOnly, or b) have a setter that either insert the message in the first position or clear all other messages and insert only the supplied message. This would also enabled us to use structured error handling while still using the more productive, simpler to read, easy to type, RETURN ERROR "Some message" to raise the AppError, which would be closer to the life long philosophy of PSC to produce a 4GL where the programmer focus on what, not how, something happens.

Posted by Laura Stern on 21-May-2015 08:27

You said:
I do not quite comprehend why the two AppError contructors cause you to always end up without a message.
 
This is not really fair.  Actually there are 3 constructors.  One takes no parameters and you need to set ReturnValue via the property or add a message with the AddMessage method to get one or the other. 
 
Of the other 2, as I said previously, AppError(<RetVal>) sets ReturnValue and the other AppError(<msg>, <msgNum>) sets the message.
 
However, I agree entirely that it was a mistake to make the one-parameter, more obvious usage set the ReturnValue rather than the error message.  This has been the source of much confusion.
 
We did not want to confuse ReturnValue with an error message.  ReturnValue is not necessarily an error message at all.  But we could have come up with another way – perhaps just requiring that ReturnValue be set manually through the property.
 
Also, the message number may not be meaningless.  We know that people sometimes use the number associated with system errors to check for specific error cases.  This is a way to define your own error codes so that callers/catchers of application generated errors can handle different error conditions differently.
 
Laura
 
 
[collapse]
From: Simon L. Prinsloo [mailto:bounce-simonvidisolvecom@community.progress.com]
Sent: Thursday, May 21, 2015 3:08 AM
To: TU.OE.Development@community.progress.com
Subject: RE: [Technical Users - OE Development] Simple Error Handling
 
Reply by Simon L. Prinsloo

To answer the original question:

ProError is the super class for AppError and SysError, but not for other errors, e.g. .Net errors.

But all errors implements the Error interface.

So you can catch the AppError and use its ReturnValue and/or any messages it contains, followed by catching the Error interface to catch anything else that is left.

Alternatively you can catch the Error interface only. If it has no messages, you can test if it is an AppError and if so, cast it and check for a ReturnValue.

I do not quite comprehend why the two AppError contructors cause you to always end up without a message somewhere, as it always complicates things and leads to unnatural code, e.g. "NEW AppError('My messages', any0meaningless-integer)" just to get the "new" structured error handling to work.

For compatibility with traditional errors, I would expect that the ReturnValue property's getter should simply map to GetMessage(1) and that it would either be a) ReadOnly, or b) have a setter that either insert the message in the first position or clear all other messages and insert only the supplied message. This would also enabled us to use structured error handling while still using the more productive, simpler to read, easy to type, RETURN ERROR "Some message" to raise the AppError, which would be closer to the life long philosophy of PSC to produce a 4GL where the programmer focus on what, not how, something happens.

Stop receiving emails on this subject.

Flag this post as spam/abuse.

[/collapse]

Posted by Thomas Mercer-Hursh on 21-May-2015 09:40

Right, Laura, it doesn't have to be meaningless, but unless one commits to a systematic program of creating numbers, it will be meaningless and I find that disturbing because it is deceptive.  I would have been much happier had AppError always set a message and ReturnValue produced the same result as GetMessage(1).

But, Simon's discussion has clarified things for me.  The context in which the question arose is a routine using Proparse so appropriate sprinkling of Error is appropriate to catch anything Proparse does.  Now that I have found an occasion to also throw an AppError, the simple thing is to add a catch block for that and avoid testing and casting and branching.  

Posted by Roger Blanchard on 21-May-2015 10:02

We use the error number extensively as we have an error message table that allows our end users to customize the error.

Posted by Jeff Ledbetter on 21-May-2015 10:07

Sweet.
 
So if the user doesn’t like “Order Not Found” they can turn it into “You entered the wrong number. What the hell is the matter with you?!”? J
 
Jeff Ledbetter
skype: jeff.ledbetter
 
[collapse]
From: rblanchard [mailto:bounce-rblanchard@community.progress.com]
Sent: Thursday, May 21, 2015 10:03 AM
To: TU.OE.Development@community.progress.com
Subject: RE: [Technical Users - OE Development] Simple Error Handling
 
Reply by rblanchard

We use the error number extensively as we have an error message table that allows our end users to customize the error.

Stop receiving emails on this subject.

Flag this post as spam/abuse.

[/collapse]

Posted by Roger Blanchard on 21-May-2015 10:09

Exactly....we deal with retailers. You sometimes have to hit a cashier over the head to get them to understand.

Posted by Evan Bleicher on 21-May-2015 12:19

[quote user="Laura Stern"]

You said:
I do not quite comprehend why the two AppError contructors cause you to always end up without a message.
 
This is not really fair.  Actually there are 3 constructors.  One takes no parameters and you need to set ReturnValue via the property or add a message with the AddMessage method to get one or the other. 
 
Of the other 2, as I said previously, AppError(<RetVal>) sets ReturnValue and the other AppError(<msg>, <msgNum>) sets the message.
 
However, I agree entirely that it was a mistake to make the one-parameter, more obvious usage set the ReturnValue rather than the error message.  This has been the source of much confusion.
 
[/quote]
I am in total agreement with Laura's observation that the overloads of the Progress.Lang.AppError constructor we selected have caused confusion.  And although we cannot change this behavior now, the motivation at the time was to provide a simple model for ABL developers to use when transitioning from the older error handling facility to the structured error handling infrastructure.  For example, within a function an ABL program can
RETURN ERROR "return value error string".
This statement sets RETURN-VALUE.
In the structured error handling model, this single statement can be replaced by the following single statement:
RETURN NEW AppError ("return value error string").
Using the alternatives mentioned would have required the new code to written in several statements.
This information does not change the observation that the model we selected has caused confusion, but I am providing it here to simply note why this decision was made.  

Posted by Mike Fechner on 21-May-2015 12:33

Laura, Evan, please don't get this wrong! I love the ABL - it only has very few design mistakes.

The constructors of the AppErtor are a good example why PSC should never run two beta programs in parallel ever....

Nobody attend the 10.1C beta where this was added due to the in parallel running 10.2A beta. So the usual suspects (I remember a discussion on this with Julian and myself involved the week after 10.1C was released and it was too late to fix this) didn't pay attention to it. So blame it on us because the 10.2A beta was too attractive :)

So next time Kris invites for a beta, join and participate. You may regret to have missed the chance to influence the language years after!

Real world experience just shows that the constructors designed that way with good intentions cause lots of confusion when using it. Now it's to late to fix this in the language design.

A personal fix is a child class of AppError with those constructors you desire. Constructors are not inherited so you are free to use whatever you want.

Von meinem Windows Phone gesendet

Von: Evan Bleicher
Gesendet: ‎21.‎05.‎2015 19:20
An: TU.OE.Development@community.progress.com
Betreff: RE: [Technical Users - OE Development] Simple Error Handling

Reply by Evan Bleicher

Laura Stern
You said:
I do not quite comprehend why the two AppError contructors cause you to always end up without a message.
 
This is not really fair.  Actually there are 3 constructors.  One takes no parameters and you need to set ReturnValue via the property or add a message with the AddMessage method to get one or the other. 
 
Of the other 2, as I said previously, AppError(<RetVal>) sets ReturnValue and the other AppError(<msg>, <msgNum>) sets the message.
 
However, I agree entirely that it was a mistake to make the one-parameter, more obvious usage set the ReturnValue rather than the error message.  This has been the source of much confusion.
 

I am in total agreement with Laura's observation that the overloads of the Progress.Lang.AppError constructor we selected have caused confusion.  And although we cannot change this behavior now, the motivation at the time was to provide a simple model for ABL developers to use when transitioning from the older error handling facility to the structured error handling infrastructure.  For example, within a function an ABL program can
RETURN ERROR "return value error string".
This statement sets RETURN-VALUE.
In the structured error handling model, this single statement can be replaced by the following single statement:
RETURN NEW AppError ("return value error string").
Using the alternatives mentioned would have required the new code to written in several statements.
This information does not change the observation that the model we selected has caused confusion, but I am providing it here to simply note why this decision was made.  
Stop receiving emails on this subject.

Flag this post as spam/abuse.

Posted by Thomas Mercer-Hursh on 21-May-2015 12:53

Evan, what would prevent returning the RETURN-VALUE for an AppError in response to Get-Messages(1) instead of the latter returning nothing?

Posted by Laura Stern on 21-May-2015 13:02

As I said earlier, ReturnValue is not the same as an error message.  That’s why I don’t like that.  And you could have both an error message and a ReturnValue.  Then what?
 
Laura
 
[collapse]
From: Thomas Mercer-Hursh [mailto:bounce-tamhas@community.progress.com]
Sent: Thursday, May 21, 2015 1:54 PM
To: TU.OE.Development@community.progress.com
Subject: RE: [Technical Users - OE Development] Simple Error Handling
 
Reply by Thomas Mercer-Hursh

Evan, what would prevent returning the RETURN-VALUE for an AppError in response to Get-Messages(1) instead of the latter returning nothing?

Stop receiving emails on this subject.

Flag this post as spam/abuse.

[/collapse]

Posted by Peter Judge on 21-May-2015 13:04

Because you can have both.
 
def var oAE as AppError.
 
oAE = new AppError("RETVAL").
oAE:AddMessage('erste', 1).
oAE:AddMessage('zweite', 2).
 
 
 
 
[collapse]
From: Thomas Mercer-Hursh [mailto:bounce-tamhas@community.progress.com]
Sent: Thursday, 21 May, 2015 13:54
To: TU.OE.Development@community.progress.com
Subject: RE: [Technical Users - OE Development] Simple Error Handling
 
Reply by Thomas Mercer-Hursh

Evan, what would prevent returning the RETURN-VALUE for an AppError in response to Get-Messages(1) instead of the latter returning nothing?

Stop receiving emails on this subject.

Flag this post as spam/abuse.

[/collapse]

Posted by Simon L. Prinsloo on 21-May-2015 14:21

As noted before, the idea was to make transition easy. Unfortunately it had the opposite effect and none of us noticed until it was too late. When you trapped an AppError, it could arise from new code, meaning that what you need to say/log lives in GetMessage(1), or it could come from that big black dark secret piece of legacy spaghetti somewhere down the call stack, so what you need lives in ReturnValue. You never know, so now you end up checking both. A lot.

I would have been perfectly happy with AppError not having a ReturnValue and all of the following resulting in identical objects (except for the part where GetMessage(1) would have different results):
a) RETURN ERROR "Some error message". 
b) RETURN NEW AppError("Some error message").
c) RETURN NEW AppError("Some error message",1234).
d) UNDO, THROW NEW AppError("Some error message").
e) e = NEW AppError(). e:AddMessage("Some error message"). UNDO, THROW e.

and these could also be identical:
a) RETURN ERROR.
b) RETURN NEW AppError().
c) UNDO, THROW NEW AppError().
d) e = NEW AppError(). UNDO, THROW e.

But as Mike said, it can't be fixed now. So in 10.1C I've derived my own AppError and overloaded both constructors taking parameters, mapping both to the one that set the first message and setting ReturnValue in both to the message string. So in my world ReturnValue was shorthand for GetMessage(1) and I was guaranteed that ReturnValue would always be populated, unless the error actually originated from a legacy "RETURN ERROR.", thus clearing out RETURN-VALUE in any case.

Today, I no longer bother. If there are 0 messages, I might check if it is an AppError and then jump through the hoops of getting hold of the ReturnValue.


This thread is closed