Data structure and exception
-
I'm attempting to write a fairly complex data structure. One part of the complexity is that all 8 data operations it supports delegate some code to virtual method. This is by design because I want the user to subclass the data structure and be able to prevent changes to happen. and / or I want to notify observers. The unfortunate side effect is: it seems there are no simple way to have all user code run at the begining or at the end of the code. Hence some user code might be called in the middle of an operation and cause an unrecoverable error. (i.e. corrupt the data structure). Do you think it's acceptable? I am thinking there are 2 possibilities: 1. it's ok. Warn the user (in the documentation), these are critical data method, mess them, mess the data! 2. data structure should be fool proof, stack all user change in a class for this purpose and run them at the end what do you think?
-
I'm attempting to write a fairly complex data structure. One part of the complexity is that all 8 data operations it supports delegate some code to virtual method. This is by design because I want the user to subclass the data structure and be able to prevent changes to happen. and / or I want to notify observers. The unfortunate side effect is: it seems there are no simple way to have all user code run at the begining or at the end of the code. Hence some user code might be called in the middle of an operation and cause an unrecoverable error. (i.e. corrupt the data structure). Do you think it's acceptable? I am thinking there are 2 possibilities: 1. it's ok. Warn the user (in the documentation), these are critical data method, mess them, mess the data! 2. data structure should be fool proof, stack all user change in a class for this purpose and run them at the end what do you think?
You can use next template in your structure to recover your data when user code throws exception:
public void SomeOperation()
{
try
{
SomeOperationBase();
}
catch(Exception)
{
// Recover your data here.
// You can throw your own exception here (don't forget to set InnerException for it).
// Or you can simply rethrow exception.
throw;
}
}protected virtual void SomeOperationBase()
{
// Your code for SomeOperation() here.
}Notice! 1. SomeOperation() is public and nonvirtual. 2. SomeOperationBase() is protected and virtual. You can also use this template to solve this problem:
The unfortunate side effect is: it seems there are no simple way to have all user code run at the begining or at the end of the code.
-- modified at 4:51 Sunday 9th July, 2006
-
You can use next template in your structure to recover your data when user code throws exception:
public void SomeOperation()
{
try
{
SomeOperationBase();
}
catch(Exception)
{
// Recover your data here.
// You can throw your own exception here (don't forget to set InnerException for it).
// Or you can simply rethrow exception.
throw;
}
}protected virtual void SomeOperationBase()
{
// Your code for SomeOperation() here.
}Notice! 1. SomeOperation() is public and nonvirtual. 2. SomeOperationBase() is protected and virtual. You can also use this template to solve this problem:
The unfortunate side effect is: it seems there are no simple way to have all user code run at the begining or at the end of the code.
-- modified at 4:51 Sunday 9th July, 2006
Thanks for answering! Doesn't work though! My Code is more like that:
void ActionImpl() { /* ... */ }
protected void Action(TextElement aParent)
{
foreach(TextElement child in this)
child.Action(); // exception might happen in child too
ActionImpl();
NotifyAction(this); // <= potential user exception here
}
protected virtual void NotifyAction(TextElement aParent)
{
// nothing, up to the subclass
// the subclass might throw an exception
}One problem is the recovering action has user notification too! (in fact it just use the reverse operation). So the recovering could fail to. (and then I have 2 exception which I should report to the user... which might be confusing). So I decided I won't recover, I will just manage to have the data in a valid state, though neither the initial nor the expected final one. An other case is:
protected void BigAction()
{
Action_1(); // subclass exception might happen here
Action_2(); // subclass exception might happen here too
}after Action_2() thrown an error I should undo Action_1(). But what if the undo throw an exception? It's all clear to me now. I should NOT recover. That was my mistake. I should report the exception straight away with as little change as possible. However I should, at least, ensure valid (even though unexpected) internal data.
-
You can use next template in your structure to recover your data when user code throws exception:
public void SomeOperation()
{
try
{
SomeOperationBase();
}
catch(Exception)
{
// Recover your data here.
// You can throw your own exception here (don't forget to set InnerException for it).
// Or you can simply rethrow exception.
throw;
}
}protected virtual void SomeOperationBase()
{
// Your code for SomeOperation() here.
}Notice! 1. SomeOperation() is public and nonvirtual. 2. SomeOperationBase() is protected and virtual. You can also use this template to solve this problem:
The unfortunate side effect is: it seems there are no simple way to have all user code run at the begining or at the end of the code.
-- modified at 4:51 Sunday 9th July, 2006
BTW my case is exactly the opposite. core work is NOT virtual. Unfortunately I have virtual "notification" method (or sometimes event, but that lead to the same logical problem). Which "might" throw an exception....
-
I'm attempting to write a fairly complex data structure. One part of the complexity is that all 8 data operations it supports delegate some code to virtual method. This is by design because I want the user to subclass the data structure and be able to prevent changes to happen. and / or I want to notify observers. The unfortunate side effect is: it seems there are no simple way to have all user code run at the begining or at the end of the code. Hence some user code might be called in the middle of an operation and cause an unrecoverable error. (i.e. corrupt the data structure). Do you think it's acceptable? I am thinking there are 2 possibilities: 1. it's ok. Warn the user (in the documentation), these are critical data method, mess them, mess the data! 2. data structure should be fool proof, stack all user change in a class for this purpose and run them at the end what do you think?
If there's a possibility that the user's code might corrupt the data (which is likely to be true if the data is not a read-only and user has sufficient rights to change it) - provide some way to the [b]user[/b] to handle it. Don't try to recover data by your own means because obviously your code have no prior knowledge that might go wrong therefore there's no guaranty that you would be able to fix all the possible mess. If there's no guaranty - don't claim it. Let the user's code do all cleaning up/fixing job in a way he/she wants. One thing that might be usefull is ability of making a copy of data so the user could try again if bad things happened with the original data. If it pays to make a copy of the data before potentially dangerous operation - let user do the decision. The bottom line is - let the user decide is data was corrupted and if it was - let user's code recover from corruption. Best regards, ----------- Igor Sukhovhttp://sukhov.net
-
If there's a possibility that the user's code might corrupt the data (which is likely to be true if the data is not a read-only and user has sufficient rights to change it) - provide some way to the [b]user[/b] to handle it. Don't try to recover data by your own means because obviously your code have no prior knowledge that might go wrong therefore there's no guaranty that you would be able to fix all the possible mess. If there's no guaranty - don't claim it. Let the user's code do all cleaning up/fixing job in a way he/she wants. One thing that might be usefull is ability of making a copy of data so the user could try again if bad things happened with the original data. If it pays to make a copy of the data before potentially dangerous operation - let user do the decision. The bottom line is - let the user decide is data was corrupted and if it was - let user's code recover from corruption. Best regards, ----------- Igor Sukhovhttp://sukhov.net
Exactly! That was one of my mistake!