![]() |
Are so many subclasses such a good idea?
Hi folks,
I noticed that the standard library has a bunch of subclasses like std::bad_alloc, std::runtime_error that derive from std::exception. I gather that in order to use one of these error subclasses, one creates an instance of that subclass, using whichever one is appropriate. But is this really a good design practice? It seems odd that the creators of std chose subclasses for different situations. Why didn't they create methods for each situation instead? Thanks. |
Re: Are so many subclasses such a good idea?
Hi
khapi@yahoo.com schrieb: > I noticed that the standard library has a bunch of > subclasses like std::bad_alloc, std::runtime_error > that derive from std::exception. [...] > But is this really a good design practice? > It seems odd that the creators of std chose subclasses > for different situations. Why didn't they create > methods for each situation instead? ??? - how do you usually throw a /method/ ? And if you want to catch these errors selectively, there is no other clean way. Furthermore that many types don't harm. So where is the problem? Marcel |
Re: Are so many subclasses such a good idea?
On Jun 12, 4:56*pm, Marcel Müller <news.5.ma...@spamgourmet.com>
wrote: > ??? - how do you usually throw a /method/ ? I meant not so much to throw a method, but to throw a value that in the catch section is handled but just one class that handles exceptions, or better yet just one function. > And if you want to catch these errors selectively, there is no other > clean way. Much cleaner: enum {ERRORCODE_UNHAPPY, ...}; try { if (whatever()) throw ERRORCODE_UNHAPPY; } catch (int e) { error_processing(e); } > Furthermore that many types don't harm. So where is the problem? Having too many subclasses obscures the meaning of what's really going on. I've seen C++ code that have 3 or 4 subclasses deep. It's hard to guess what the deeper classes really do. |
Re: Are so many subclasses such a good idea?
khapi@yahoo.com wrote:
> On Jun 12, 4:56*pm, Marcel Müller <news.5.ma...@spamgourmet.com> > wrote: > >> ??? - how do you usually throw a /method/ ? > > I meant not so much to throw a method, but to throw a value > that in the catch section is handled but just one class > that handles exceptions, or better yet just one function. > >> And if you want to catch these errors selectively, there is no other >> clean way. > > Much cleaner: > > enum {ERRORCODE_UNHAPPY, ...}; > try { > if (whatever()) > throw ERRORCODE_UNHAPPY; > } > catch (int e) { > error_processing(e); > } And where is the _selective_ catching of errors? Think about void f ( void ) { try { // some code that might throw } catch ( some_exception const & e ) { } } void g ( void ) { try { f(); } catch ( some_other_exception const & e ) { ... } } The point is: different exceptions can rise up in the call stack to different levels. The type determines which catch handler is used. >> Furthermore that many types don't harm. So where is the problem? > > Having too many subclasses obscures the meaning of > what's really going on. I've seen C++ code that have > 3 or 4 subclasses deep. It's hard to guess what > the deeper classes really do. That seems to be more a problem of documentation and the naming scheme employed rather than the depth of the derivation. Besides, with standard exception classes, they all do the same (provide a message by means of the what() method). The type system is just used to classify errors and allow to catch exceptions at the right level in the call stack. Best Kai-Uwe Bux |
Re: Are so many subclasses such a good idea?
On Jun 12, 5:49 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> And where is the _selective_ catching of errors? Here: try { if (a) throw(UNHAPPY); if (b) throw(UNHAPPIER); if (c) throw(UNHAPPIEST); } catch (int which) { switch (which) { case UNHAPPY: ... break; case UNHAPPIER: ... break; case UNHAPPIEST: ... break; } } > The point is: different exceptions can rise up in the call stack to > different levels. The type determines which catch handler is used. True, that reinforces C++'s compile-time typing, which some consider to be an advantage of C++. |
Re: Are so many subclasses such a good idea?
khapi@yahoo.com wrote:
> On Jun 12, 5:49 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote: > >> And where is the _selective_ catching of errors? > > Here: > try { > if (a) > throw(UNHAPPY); > if (b) > throw(UNHAPPIER); > if (c) > throw(UNHAPPIEST); > } catch (int which) { > switch (which) { > case UNHAPPY: ... break; > case UNHAPPIER: ... break; > case UNHAPPIEST: ... break; > } > } Because that's a LOT cleaner. |
Re: Are so many subclasses such a good idea?
khapi@yahoo.com wrote:
> Hi folks, > > I noticed that the standard library has a bunch of > subclasses like std::bad_alloc, std::runtime_error > that derive from std::exception. > > I gather that in order to use one of these error > subclasses, one creates an instance of that subclass, > using whichever one is appropriate. > > But is this really a good design practice? > It seems odd that the creators of std chose subclasses > for different situations. Why didn't they create > methods for each situation instead? > Because that's not extensible. What if I want a new exception type class my_exception : std::public exception { // internals redacted }; How would you provide that in your scheme of things? |
Re: Are so many subclasses such a good idea?
"Daniel T." <daniel_t@earthlink.net> writes:
> khapi@yahoo.com wrote: >> On Jun 12, 5:49 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote: >> >> > And where is the _selective_ catching of errors? >> >> Here: >> try { >> if (a) >> throw(UNHAPPY); >> if (b) >> throw(UNHAPPIER); >> if (c) >> throw(UNHAPPIEST); >> } catch (int which) { >> switch (which) { >> case UNHAPPY: ... break; >> case UNHAPPIER: ... break; >> case UNHAPPIEST: ... break; >> } >> } > > From the above, it looks like you haven't quite gotten the hang of what > polymorphism is for. Polymorphism allows one to remove all those > duplicated switch statements. It was a counter-example! The reason why it's good to have a lot of subclasses is indeed to use polymorphism. try{ doSomething(); }catch(UnhappinesDegree e){ e->recover(); } -- __Pascal Bourguignon__ |
Re: Are so many subclasses such a good idea?
Chris Thomasson wrote:
[...] > > The C++ exception handling mechanism is very expressive. I personally > like it a lot. Here is another example. Take a mutex class which can > throw exceptions. Here is one way to write it: > __________________________________________________ _________________ > class mutex_with_exceptions { > pthread_mutex_t m_mtx; > > [...]; > > public: > struct error { > struct base {}; > > struct lock { > struct base : public error::base {}; > struct invalid : public lock::base {}; > struct priority_violation : pubilc lock::invalid {}; > struct deadlock : public lock::base {}; > struct max_recursion : public lock::base {}; > > static void raise_status(int const status) { > switch (status) { > case EINVAL: > throw priority_violation(); > case EAGAIN: > throw max_recursion(); > case EDEADLK: > throw deadlock(); > default: > assert(false); > std::unexpected(); > } > } > }; > > struct unlock { > struct base : public error::base {}; > struct not_owner : public unlock::base {}; > > static void raise_status(int const status) { > switch (status) { > case EPERM: > throw not_owner(); > default: > assert(false); > std::unexpected(); > } > } > }; > }; > > public: > void lock() { > int const status = pthread_mutex_lock(&m_mtx); > if (status) { > error::lock::raise_status(status); > } > } > > void unlock() { > int const status = pthread_mutex_unlock(&m_mtx); > if (status) { > error::unlock::raise_status(status); > } > } > }; I must say: VERY NICE :) > __________________________________________________ _________________ > > > > The exception hierarchy for the `mutex_with_exceptions' class is verbose. > > > Any thoughts? I like this explanation. Just small remark - your base class doesn't inherit from std::exception |
Re: Are so many subclasses such a good idea?
On Jun 12, 10:51 pm, kh...@yahoo.com wrote:
> Hi folks, > > I noticed that the standard library has a bunch of > subclasses like std::bad_alloc, std::runtime_error > that derive from std::exception. > > I gather that in order to use one of these error > subclasses, one creates an instance of that subclass, > using whichever one is appropriate. > > But is this really a good design practice? > It seems odd that the creators of std chose subclasses > for different situations. Why didn't they create > methods for each situation instead? > > Thanks. You should differentiate between exception-classes and 'normal' classes when looking at the inheritance trees. For 'normal' classes, it is usually a bit suspect to have a very deep inheritance tree (although there will probably be exceptions). For exception-classes, the hierarchy also gives an indication how the different exception-classes are related to each other and a deep inheritance tree often works good. For example, you have the following errors that can be reported: index- out-of-range, out-of-memory, io-error. The io-error classification can be further divided in network-error and file-error. The network-error classification can be divided into host-not-found, link-lost and connection-refused. The file-error classification can be divided into file-not-existing and file-not-accessible. If you model this as a class hierarchy, it is immediately clear that file-not-existing and file-not-accessible belong to the bigger category of file-errors. And if you chose to handle all io-errors identically at some level, you don't even have to know that there are more specific types below that level, nor do you have to change anything when someone adds a write-error to the category of file- errors. Try doing that with numeric error codes. Bart v Ingen Schenau |
| All times are GMT. The time now is 04:27 AM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.