Data structure and exception

  • Thread starter Thread starter Lloyd Dupont
  • Start date Start date
L

Lloyd Dupont

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?
 
Lloyd said:
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?

A good approach in situations like this is to separate the functionality of
your class from the extensibility points of your class. Rather than:

class Base
{
public vitrual void A() {}
}

use:

class Base
{
public void A()
{
// stuff that comes before the extension point
// (e.g. check invariants and pre-conditions, do base-class
processing)

OnA();

// stuff that comes after the extention point
// (e.g. check invariants and post-conditions)
}

protected virtual void OnA() {}
}

This way, your clients override OnA, but not A itself. You, as the
designer, retain control over where client code is inserted, so you can
still maintain (and check) invariants in the base class and know that
someone deriving from your class can't circumvent your checks by forgetting
to call the base class version (or by calling it in the wrong place).

-cd
 
Hi Carl, thanks for answering!

Anyway it's already like that but a bit more complex:

class Data
{
public void A()
{
B(); // if B() fail, C() will never happen
C();
OnA();
}
public virtual OnA() { /* potential adverse user code */ }


public void B()
{
// stuff ...
OnB();
}
public virtual OnB() { /* potential adverse user code */ }


public void C()
{
// stuff...
OnC();
}
public virtual OnC() { /* potential adverse user code */ }
}
// OnA(), OnB(), OnC() can't be removed, they are used by other part of the
API to track elementary change

However I was able to get around it.
All user notifications happen now in such a way that user exception let the
data in an unexpected, yet correct, state.
Although observers might get corrupted in the process, but it's not as
important/bad.

I no longer try to undo partial change (which could led to other exceptions
and I had no idea how to handle that correctly).
 
Back
Top