Reputation: 3601
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
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
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
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