shawnhcorey
shawnhcorey

Reputation: 3601

Encapsulation and Exceptions

I'm designing my own OO language and was happily going along until I hit exceptions. It seems to me that exceptions break encapsulation.

For example, if class A has an object of class B, B has C, and C has X, which throws an exception to A, the code in A must not only know about X but also B and C to handle it correctly. You can tell this because if you replace C with D, A exception's handler will have to change to extract the relevant information from the call stack.

The only way I can think of around this problem is to have exceptions as part of the class' API so that they propagate back up the calling stack one caller at a time. And they should re-interrupt the exception in their own terms.

Here's an example. Trend is a class for analyzing statistical trends and it has a method, slope, for calculating the slope of a line from two points.

method slope
    given
        Point 1st
        Point 2nd
    returns
        Number m
    except
        when infinite slope

    m gets
        ( 2nd's y - 1st's y ) / ( 2nd's x - 1st's x )
    except
        when any divide by zero
            declare infinite slope
        when overflow of ( 2nd's y - 1st's y )
            declare infinite slope
        when overflow of ( 2nd's x - 1st's x )
            instead do m gets 0
        when overflow of ( 2nd's y - 1st's y ) / ( 2nd's x - 1st's x )
            declare infinite slope
        when any underflow
            instead use 0

end of method slope

Is there a better way to do this?

Upvotes: 3

Views: 867

Answers (3)

umlcat
umlcat

Reputation: 4143

Im agree that Exceptions sounds more Structured that Object-and-Class-Oriented.

However, allow to solve dealing with errors.

For example, ... ... to extract the relevant information from the call stack.

Your example in C++ -like pseudocode:

class XClass {
  public: 
    void doSomething() { throw new MyException(); }
}

class CClass {
  public: 
    XClass X;
}

class BClass {
  public: 
    CClass C;
}

class AClass {
  public: 
    BClass B;
}

void main()
{
  AClass A = new AClass ();

  // exception here:
  A.B.C.X.doSomething();
}

"A" object doesn't have to know about "X", or viceversa, regarding exceptions. There should be an exception stack, which, all objects add or remove execution data.

"pure C" doesn't have exceptions, but, they can be emulated. You may want to search for the "setjmp" library, and see can those functions interact with the stack. Those knowledge may help you implement exceptions:

http://www.cplusplus.com/reference/clibrary/csetjmp/

P.D. Offtopic suggestion: add c++ namespaces, or pascal modules, to your progr. lang., you won't regret it.

Upvotes: 0

munificent
munificent

Reputation: 12364

Real-world exceptions fall into one of three rough categories:

  • System exceptions are thrown when fatal errors in the underlying runtime occur, things like out of memory, stack overflow, or perhaps security violations. These generally shouldn't be caught, and in many cases can't be caught. They basically use the exception system in order to take down the system (relatively) gracefully and report the final stack trace to the developer.

  • Programmatic exceptions are thrown when the code is doing something incorrect. Things like invalid arguments, calling methods on null pointers, out of bounds errors. These shouldn't be caught: instead the code that causes them to be thrown should be fixed. They use the exception system to avoid having a more or less redundant assert system that does most of the same things.

  • Runtime exceptions are thrown when something bad happens that cannot be programmatically prevented. They are thrown when an unexpected circumstance has occurred, but its rare enough that you don't want to clutter up the main API with error codes, etc. These are things like file IO errors, network problems, parse errors, etc. These exceptions will usually be specific to the API that's throwing them. These are the only kind of exceptions that should be typically caught.

If you agree with the above breakdown, then encapsulation only effects the third category. For the other two, the exception isn't caught in code, so it doesn't matter. For the third kind of exception, yes, I think you generally should catch the exception and translate it to different exception that's appropriate the layer that's rethrowing it. This is why most exception systems in other languages support something like "InnerException" where you can attach the previous lower-level exception that led to the current one.

Upvotes: 2

user207421
user207421

Reputation: 310883

if you replace C with D, A exception's handler will have to change to extract the relevant information from the call stack.

Not the way exception handlers are usually implemented. The intermediate called classes may not even exist when A is compiled, so building that dependency into A is not only hard but in principle infeasible.

Upvotes: 0

Related Questions