Error handling in X# vs VO
Error handling in X# vs VO
Hi,
in my VO code I'm using begin/end sequence very often to control where an error is occurring, and to inhibit that the program crashes because of a foreseable error.
The globally set errorblock helps a lot to keep my code small.
In X# there is no global error handler available. Therefore I'm thinking about using try/end try in much fewer places because the needed local error handling blows up my code - I have methods where the error handling has more lines of code than the processing itself, and there is the risk to not see the error because it is handled internally and not passed up to the calling code.
I know I can throw my own exception, and pass the current exception as InnerException, but I have yet to find my solution how to
handle this entire thing.
Maybe someone of you has some suggestion.....
Wolfgang
in my VO code I'm using begin/end sequence very often to control where an error is occurring, and to inhibit that the program crashes because of a foreseable error.
The globally set errorblock helps a lot to keep my code small.
In X# there is no global error handler available. Therefore I'm thinking about using try/end try in much fewer places because the needed local error handling blows up my code - I have methods where the error handling has more lines of code than the processing itself, and there is the risk to not see the error because it is handled internally and not passed up to the calling code.
I know I can throw my own exception, and pass the current exception as InnerException, but I have yet to find my solution how to
handle this entire thing.
Maybe someone of you has some suggestion.....
Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
- ArneOrtlinghaus
- Posts: 412
- Joined: Tue Nov 10, 2015 7:48 am
- Location: Italy
Error handling in X# vs VO
I have regretted inserting begin/end/try blocks without recover section. So I have tried to check every such usage on correct error handling in the same code part or a code part in an upper code part. I have tried to use a global try block, but together with the GUI-Classes this cannot trap errors correctly if errors appear in events. So a main task in our preparation to X# was to insert as many additional begin/end/try blocks in program parts that call much other code. For example a pushbutton method should include such a blocks . For avoiding having to insert such a sequence in every application pushbutton method, I have modified methods in the GUI-Classes and in our framework derived from the GUI-Classes so that these basic mechanisms contain already correct handling of exceptions.
(Exception handling is nice, but also risky. I remember a project a colleague made in JAVA many years ago. He was so proud handling EVERYTHING with exceptions. But he forgot to decode the exceptions correctly in the calling parts. So we spent much time discovering the real reason for strange exceptions happening at the customer's site that put us in complete wrong directions for searching the reason.)
(Exception handling is nice, but also risky. I remember a project a colleague made in JAVA many years ago. He was so proud handling EVERYTHING with exceptions. But he forgot to decode the exceptions correctly in the calling parts. So we spent much time discovering the real reason for strange exceptions happening at the customer's site that put us in complete wrong directions for searching the reason.)
-
- Posts: 248
- Joined: Fri Oct 14, 2016 7:09 am
Error handling in X# vs VO
Hi Wolfgang,
I have a different approach.... I never allow exceptions to propagate up through code. Any method that may be subject to some sort of exception (eg anything accessing data) always returns a 'Result' object that can wrap up any error.
Let's say I have a method that should return an int. In the method I'll use try/catch as normal, but the return type of the method won't be int, it'll be MyResultObject<int>. In the calling method you can then interrogate the result object to see what happened, without having to deal directly with an exception.
My result class is something like this...
Obviously if there's some runtime error that's not caught by this it'll still blow up the program, but this organises everything else and makes error trapping much more manageable.
Not sure if I answered the question or not to be honest!!
Nick
I have a different approach.... I never allow exceptions to propagate up through code. Any method that may be subject to some sort of exception (eg anything accessing data) always returns a 'Result' object that can wrap up any error.
Let's say I have a method that should return an int. In the method I'll use try/catch as normal, but the return type of the method won't be int, it'll be MyResultObject<int>. In the calling method you can then interrogate the result object to see what happened, without having to deal directly with an exception.
My result class is something like this...
Code: Select all
public class CIOResult<T>
{
/// <summary>
/// Enum of different outcomes eg Success, NotFound, etc
/// </summary>
public CIOResultType Result { get; set; }
/// <summary>
/// Optional Exception object that can be returned for debugging.
/// </summary>
public Exception CIOException { get; set; }
/// <summary>
/// Construtor used when a call has failed, and an exception is to be returned.
/// </summary>
/// <param name="result">Result enum value.</param>
/// <param name="excep">Exception object.</param>
public CIOResult(CIOResultType result, Exception excep)
{
Result = result;
CIOException = excep;
}
/// <summary>
/// Constructor used when a value is to be returned.
/// </summary>
/// <param name="result">Result enum value.</param>
/// <param name="cargo">Data object to be returned.</param>
public CIOResult(CIOResultType result, T cargo)
{
Result = result;
Cargo = cargo;
}
/// <summary>
/// Constructor used when only the result is to be returned.
/// </summary>
/// <param name="result">Enum value of result.</param>
public CIOResult(CIOResultType result)
{
Result = result;
}
/// <summary>
/// Constructor for successful completion and to return a data object.
/// </summary>
/// <param name="cargo">Data object to return.</param>
public CIOResult(T cargo) : base()
{
Result = CIOResultType.success;
Cargo = cargo;
}
/// <summary>
/// Constructor for successful completion but without a data object.
/// </summary>
public CIOResult()
{
Result = CIOResultType.success;
}
/// <summary>
/// Data object to be included in the CIOResult object.
/// </summary>
public T Cargo { get; set; }
}
Not sure if I answered the question or not to be honest!!
Nick
Error handling in X# vs VO
Hi Nick,
Any method that may be subject to some sort of exception (eg anything accessing data) always returns a 'Result' object that can wrap up any error.
This is really a nice idea!
I have to think about, but it could be that I will steal it <g>.
Wolfgang
Any method that may be subject to some sort of exception (eg anything accessing data) always returns a 'Result' object that can wrap up any error.
This is really a nice idea!
I have to think about, but it could be that I will steal it <g>.
Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
Error handling in X# vs VO
Hi Nick,
based on your code I have now written the following class:
And this a sample how to use it:
Thank you again!
Wolfgang
P.S. Did I mentioned that I like generics?
based on your code I have now written the following class:
Code: Select all
public class ResultEx<T>
protect _oResult as T
protect _oException as Exception
protect _oCargo as object
constructor( oResult as T, oException as Exception, oCargo as object )
_oResult := oResult
_oException := oException
_oCargo := oCargo
return
constructor( oResult as T, oException as Exception )
self( oResult, oException, null )
return
constructor( oResult as T )
self( oResult, null, null )
return
constructor( oResult as T, oCargo as object )
self( oResult, null, oCargo )
return
public property Result as T get _oResult set _oResult := value
public property Exception as Exception get _oException set _oException := value
public property Cargo as object get _oCargo set _oCargo := value
end class
Code: Select all
function TestResultEx( lSuccess as logic ) as void
local oResult as ResultEx<logic>
oResult := ExecuteTestResultEx( lSuccess )
if oResult:Result
System.Console.WriteLine( "Execution succeeded" )
else
System.Console.WriteLine( String.Format( "Execution failed with error message '{0}'", oResult:Exception:Message ) )
endif
function ExecuteTestResultEx( lSuccess as logic ) as ResultEx<logic>
local oResult as ResultEx<logic>
oResult := ResultEx<logic>{ true }
try
if lSuccess == false
throw Exception{ "I have to fail" }
endif
catch oEx as Exception
oResult:Exception := oEx
oResult:Result := false
end try
return oResult
Wolfgang
P.S. Did I mentioned that I like generics?
Wolfgang Riedmann
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
Error handling in X# vs VO
Hi Arne,
I have regretted inserting begin/end/try blocks without recover section.
In VO, this works well because of the global error handler.
Such a code in VO does what it should:
because it shows an eventual error message using the global error handler.
But in .NET this does not reports the error, unfortunately.
I have lots of these constructs in my code, unfortunately.
Wolfgang
I have regretted inserting begin/end/try blocks without recover section.
In VO, this works well because of the global error handler.
Such a code in VO does what it should:
Code: Select all
function MyFunc() as logic
local lReturn as logic
lReturn := true
begin sequence
< processing something >
recover
lReturn := false
end sequence
return lReturn
But in .NET this does not reports the error, unfortunately.
I have lots of these constructs in my code, unfortunately.
Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
-
- Posts: 248
- Joined: Fri Oct 14, 2016 7:09 am
Error handling in X# vs VO
Hi Wolfgang,
That's not quite how I'd do it. My intention was that Cargo is the generic object to hold any data or return value from the method call, and Result is something to give info on the actual process (success, failure, no data found, exception thrown, etc), so can be an enum of pre-established values to describe different outcomes.
So when you return a result object, the generic T type is the return type, not the type of process result. And the process outcome can be used to direct code for error handling etc in the calling method.
So if you had ResultEx<MyObject> as a return value from a method you'd know there was an object of type MyObject in Cargo and Result contains something like success/failure/notfound which gives you info about the outcome of the called method. This makes it easy to strongly type everything as well.
Nick
That's not quite how I'd do it. My intention was that Cargo is the generic object to hold any data or return value from the method call, and Result is something to give info on the actual process (success, failure, no data found, exception thrown, etc), so can be an enum of pre-established values to describe different outcomes.
So when you return a result object, the generic T type is the return type, not the type of process result. And the process outcome can be used to direct code for error handling etc in the calling method.
So if you had ResultEx<MyObject> as a return value from a method you'd know there was an object of type MyObject in Cargo and Result contains something like success/failure/notfound which gives you info about the outcome of the called method. This makes it easy to strongly type everything as well.
Nick
- ArneOrtlinghaus
- Posts: 412
- Joined: Tue Nov 10, 2015 7:48 am
- Location: Italy
Error handling in X# vs VO
Hi Wolfgang,
yes, I know that it works in VO and we have had recoverable errors with this solution many thousands of times. However I haven't found any similar solution in X#. The global error blocks as proposed by different colleagues like Dieter Crispien worked with batch executions, but did not work correctly with the GUI in my tests.
Arne
yes, I know that it works in VO and we have had recoverable errors with this solution many thousands of times. However I haven't found any similar solution in X#. The global error blocks as proposed by different colleagues like Dieter Crispien worked with batch executions, but did not work correctly with the GUI in my tests.
Arne
Error handling in X# vs VO
Hi Nick,
It is more the cargo member that I currently don't need, but it could be useful, so I have implemented it.
And I have added a subclass like this one (to cover the most used return type without generic):
Wolfgang
Yes, I understand that from your code. But I prefer it the way as I have written it. Most of the times a logic return is enough for me, and very often I return some sort of object. And if I need a result enumeration, I can simply use that as the result type.That's not quite how I'd do it. My intention was that Cargo is the generic object to hold any data or return value from the method call, and Result is something to give info on the actual process (success, failure, no data found, exception thrown, etc), so can be an enum of pre-established values to describe different outcomes.
It is more the cargo member that I currently don't need, but it could be useful, so I have implemented it.
And I have added a subclass like this one (to cover the most used return type without generic):
Code: Select all
class LogicResultEx inherit ResultEx<logic>
constructor( lResult as logic, oException as Exception, oCargo as object )
super( lResult, oException, oCargo )
return
constructor( oResult as logic, oException as Exception )
self( oResult, oException, null )
return
constructor( oResult as logic )
self( oResult, null, null )
return
constructor( oResult as logic, oCargo as object )
self( oResult, null, oCargo )
return
Wolfgang Riedmann
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
Error handling in X# vs VO
Hi Arne,
Maybe they can give us the possibility to set a global error handler, maybe using the ErrorBlock() function from VO, and put a call to that in the recover clause of the begin/end sequence construct.
I had asked for that when the development had started, but probably it was too early and it either got lost or it was forgotten.
This is one of the incompatibilities between VO and X I'm be most afraid of.
Wolfgang
I do think that the development team needs to add something to the translation of begin/end sequence.However I haven't found any similar solution in X#. The global error blocks as proposed by different colleagues like Dieter Crispien worked with batch executions, but did not work correctly with the GUI in my tests.
Maybe they can give us the possibility to set a global error handler, maybe using the ErrorBlock() function from VO, and put a call to that in the recover clause of the begin/end sequence construct.
I had asked for that when the development had started, but probably it was too early and it either got lost or it was forgotten.
This is one of the incompatibilities between VO and X I'm be most afraid of.
Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it