473,379 Members | 1,174 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,379 software developers and data experts.

Re: Are so many subclasses such a good idea?

Hi

kh***@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
Jun 27 '08 #1
12 1473
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.
Jun 27 '08 #2
kh***@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
Jun 27 '08 #3
On Jun 12, 5:49 pm, Kai-Uwe Bux <jkherci...@gmx.netwrote:
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++.

Jun 27 '08 #4
kh***@yahoo.com wrote:
On Jun 12, 5:49 pm, Kai-Uwe Bux <jkherci...@gmx.netwrote:
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.
Jun 27 '08 #5
kh***@yahoo.com wrote:
On Jun 12, 5:49 pm, Kai-Uwe Bux <jkherci...@gmx.netwrote:
>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.
Jun 27 '08 #6
<kh***@yahoo.comwrote in message
news:8b**********************************@m3g2000h sc.googlegroups.com...
On Jun 12, 5:49 pm, Kai-Uwe Bux <jkherci...@gmx.netwrote:
>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++.
Why use the switch statement when the nature of the try/catch functionality
can do this for you? Example:
namespace error {
struct base {};
namespace mood {
struct base : public error::base {};
struct unhappy : public mood::base {};
struct unhappier : public mood::base {};
struct unhappiest : public mood::base {};
}
}
try {
if (a) { throw error::mood::unhappy(); }
if (b) { throw error::mood::unhappier(); }
if (c) { throw error::mood::unhappiest(); }

} catch (error::mood::unhappiest const& e) {

} catch (error::mood::unhappier const& e) {

} catch (error::mood::unhappy const& e) {

} catch (error::mood::base const& e) {

} catch (error::base const& e) {

} catch (...) {

}

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);
}
}
};
__________________________________________________ _________________

The exception hierarchy for the `mutex_with_exceptions' class is verbose.
Any thoughts?

Jun 27 '08 #7
"Daniel T." <da******@earthlink.netwrites:
kh***@yahoo.com wrote:
>On Jun 12, 5:49 pm, Kai-Uwe Bux <jkherci...@gmx.netwrote:
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__
Jun 27 '08 #8
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
Jun 27 '08 #9
On 2008-06-13 00:26, kh***@yahoo.com wrote:
On Jun 12, 5:49 pm, Kai-Uwe Bux <jkherci...@gmx.netwrote:
>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;
}
}
What if not all errors can be handled at the same place:

class e1;
class e2;
class e3;

void f()
{
try {
if (a) throw e1;
if (b) throw e2;
if (c) throw e3;
}
catch (e1) {
// ...
}
}

void g()
{
try {
f();
}
catch (e2) {
// ....
}
}

int main()
{
try {
g();
}
catch (e3) {
// ...
}
}

Can not be solved with an int unless you rethrow those that can not be
handled.

--
Erik Wikström
Jun 27 '08 #10
kh***@yahoo.com schrieb:
On Jun 12, 5:49 pm, Kai-Uwe Bux <jkherci...@gmx.netwrote:
>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;
}
}
How to boundle additional information with the exception, like the
filename of the file that couldn't be opened, or the IP-Address of the
connection attempt that didn't worked out?

Using a class as exception object, you can attach valuable information
to the exception.
>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++.
And C++'s run-time type information. You don't know until run-time,
which type of exception will be thrown.

--
Thomas
Jun 27 '08 #11
What if not all errors can be handled at the same place:
....
>
Can not be solved with an int unless you rethrow those that can not be
handled.
Why rethrow? One can just create a centralized
handler function.

void central_handler(int e)
{
...
}
void func() {
try {
something();
}
catch (int e) {
central_handler(e);
}
}
void func2() {
try {
something2();
}
catch (int e) {
central_handler(e);
}
}

And for functions that require immediate
action that can be done in the catch.
Jun 27 '08 #12
On 22 Jun., 15:22, kh...@yahoo.com wrote:
What if not all errors can be handled at the same place:
...
Can not be solved with an int unless you rethrow those that can not be
handled.

Why rethrow? One can just create a centralized
handler function.

void central_handler(int e)
{
*...}

void func() {
* try {
* * *something();
* }
* catch (int e) {
* * *central_handler(e);
* }}

void func2() {
* try {
* * *something2();
* }
* catch (int e) {
* * *central_handler(e);
* }

}

And for functions that require immediate
action that can be done in the catch.
But that central error-handler would probably only be central for f. I
assume that your program is not of the type that every error is
handled in the same manner, no matter the context. If this is the
case, your program would be quite unusual.

/Peter
Jun 27 '08 #13

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: jaekim | last post by:
Hi. I am wondering if it is a good idea to replicate sql server db files using frs. I don't really know how the frs works, so does frs replicates the whole database from time to time or just...
12
by: Generic Usenet Account | last post by:
I am going through some legacy code that has an "isNull()" method defined on certain classes. I can see that this can be a good way to eliminate certain types of crashes, by making this the first...
4
by: GiladP1 | last post by:
Hi, I want to copy protect my application. I want to limit its use for a given period of time, say 30 days, after which a license key will be needed. There are various issues to consider here...
3
by: Andras Tantos | last post by:
Hi! I had a discussion in the other day about the usefullness and validity of the following (non-std) C extension in PICC: static bit BitVar @ 0x20*8+0; This would mean that a static...
54
by: sam.s.kong | last post by:
Hi! I've been programming ASP for 5 years and am now learning PHP. In ASP, you can use GetRows function which returns 2 by 2 array of Recordset. Actually, it's a recommended way in ASP when you...
0
by: Charles D Hixson | last post by:
I was reading through old messages in the list and came up against an idea that I thought might be of some value: "Wouldn't it be a good idea if one could "rewind" an iterator?" Not stated in...
3
by: piotr maliñski | last post by:
I'm planning to wite a fully featured wiki in Python in one of frameworks. I've seen some notes about wiki/documentation management scripts that use SVN as a data storage/versioning. I've been...
2
by: pigeonrandle | last post by:
Hi, My application creates a project that is structured like a tree, so i want to use a treeview to display it to the user. Would it be a good idea to create the various parts of project as...
7
by: elgiei | last post by:
Good morning at all, i have to implement a server,that every n-seconds (eg. 10sec) sends to other clients,which files and directory has been deleted or modified. i build a n-tree, for each...
5
by: mike3 | last post by:
Hi. Is this a good idea?: <begin code> /* Addition operator: += */ const BigFix &BigFix::operator+=(const BigFix &rhs) { ErrorType err; int lhs_sign = sign, rhs_sign = rhs.sign;
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.