From: DeMarcus on 2 Feb 2010 06:34 The debate about dynamically or statically checked exceptions will never end. Still, I would like to propose a compromise. Can we have a flag in the compiler that, when set, will do a static check for throw(), i.e. no-throw functions? That would help a lot when trying to write exception safe code with guarantees [1][2]. [1] http://en.wikipedia.org/wiki/Exception_guarantees [2] http://www.boost.org/community/exception_safety.html Regards, Daniel -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Goran on 2 Feb 2010 21:46 On Feb 3, 12:34 am, DeMarcus <use_my_alias_h...(a)hotmail.com> wrote: > The debate about dynamically or statically checked exceptions will never > end. Still, I would like to propose a compromise. > > Can we have a flag in the compiler that, when set, will do a static > check for throw(), i.e. no-throw functions? > > That would help a lot when trying to write exception safe code with > guarantees [1][2]. > > [1]http://en.wikipedia.org/wiki/Exception_guarantees > [2]http://www.boost.org/community/exception_safety.html Well, it certainly would. However... 1. That's IMO really hard to do in practice. In calls to existing code without source, compiler has no idea whether it will throw or not, unless it's compiled with same flags. Then, innocuous calls like operator new can be overriden to throw or not, at runtime. that would be impossible to detect. 2. often, a no-throw guarantee is not at the function boundary, but rather just a couple of lines in an existing one. So that makes your idea not-far-reaching-enough (e.g. something like "nothrow {}" would be even more useful. For example, recently someone asked here "what if creation of scope guard throws" and the answer to that is "your job to make sure it does not"; no-one in their right mind would put scope guard creation in a function. Goran. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: DeMarcus on 3 Feb 2010 15:41 Goran wrote: > On Feb 3, 12:34 am, DeMarcus <use_my_alias_h...(a)hotmail.com> wrote: >> The debate about dynamically or statically checked exceptions will never >> end. Still, I would like to propose a compromise. >> >> Can we have a flag in the compiler that, when set, will do a static >> check for throw(), i.e. no-throw functions? >> >> That would help a lot when trying to write exception safe code with >> guarantees [1][2]. >> >> [1]http://en.wikipedia.org/wiki/Exception_guarantees >> [2]http://www.boost.org/community/exception_safety.html > > Well, it certainly would. However... > Thanks Goran! You gave me perfect feedback. Look here: > 1. That's IMO really hard to do in practice. In calls to existing code > without source, compiler has no idea whether it will throw or not, > unless it's compiled with same flags. Then, innocuous calls like > operator new can be overriden to throw or not, at runtime. that would > be impossible to detect. > Yes, you are completely right. However, the idea is that the compiler flag should only give a warning, and only when set. Therefore, when the compiler gives me a warning about someFunction() throw() that uses another function without throw(), I can choose to embrace it with try/catch(...). Now I now that at least someFunction() won't throw and crash on me when the exception reaches the caller that "must never throw". This way we can make the our own code provide complete no-throw guarantees, but not without help from the compiler's warnings. > 2. often, a no-throw guarantee is not at the function boundary, but > rather just a couple of lines in an existing one. So that makes your > idea not-far-reaching-enough (e.g. something like "nothrow {}" would > be even more useful. For example, recently someone asked here "what if > creation of scope guard throws" and the answer to that is "your job to > make sure it does not"; no-one in their right mind would put scope > guard creation in a function. > I think that particular someone was me. ;) I try understand all this about exception safety, so please excuse my lack of experience. Anyway, you write "your job is to make sure it does not" (throw). It is my job, yes, but if the compiler could do the job for me, or at least warn about a potential meltdown, my job would so much less stressful. Let's take a good example. Nowhere can I find proper documentation whether std::vector's pop_back() throws or not. On the contrary, if we look at the synopsis for boost::shared_ptr (http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/shared_ptr.htm) we see that most functions are documented with "// never throws" How do we know that? Just because they write it? Or do they actually do a try/catch(...) in the code, and if so, why not declare those functions with throw()? When you write "your job is to make sure it does not" (throw), I claim that with the lack of documentation and compiler help, this is not an easy task! You also write "no-one in their right mind would put scope guard creation in a function". I don't think I understand what you meant. I would appreciate if you explained that. Thanks, Daniel > > Goran. > > -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Goran on 4 Feb 2010 04:24 On Feb 4, 9:41 am, DeMarcus <use_my_alias_h...(a)hotmail.com> wrote: > > 1. That's IMO really hard to do in practice. In calls to existing code > > without source, compiler has no idea whether it will throw or not, > > unless it's compiled with same flags. Then, innocuous calls like > > operator new can be overriden to throw or not, at runtime. that would > > be impossible to detect. > > Yes, you are completely right. However, the idea is that the compiler > flag should only give a warning, and only when set. Therefore, when the > compiler gives me a warning about someFunction() throw() that uses > another function without throw(), I can choose to embrace it with > try/catch(...). Now I now that at least someFunction() won't throw and > crash on me when the exception reaches the caller that "must never throw". > > This way we can make the our own code provide complete no-throw > guarantees, but not without help from the compiler's warnings. Yes, that seems possible. Note, however that something innocuous like std::string s("well now") might throw (bad_alloc is my favorite when talking exceptions ;-)). Or, many calls to STL might throw. And standard library does not use exception specification, nor do many others. So one innocuous library call somewhere and your own spec becomes invalid (think maintenance). (I guess there are reasons why standard and other libraries don't use throw() and that this is related to the spec of throw() and history.) > > 2. often, a no-throw guarantee is not at the function boundary, but > > rather just a couple of lines in an existing one. So that makes your > > idea not-far-reaching-enough (e.g. something like "nothrow {}" would > > be even more useful. For example, recently someone asked here "what if > > creation of scope guard throws" and the answer to that is "your job to > > make sure it does not"; no-one in their right mind would put scope > > guard creation in a function. > > I think that particular someone was me. ;) I try understand all this > about exception safety, so please excuse my lack of experience. > Anyway, you write "your job is to make sure it does not" (throw). It is > my job, yes, but if the compiler could do the job for me, or at least > warn about a potential meltdown, my job would so much less stressful. > > Let's take a good example. Nowhere can I find proper documentation > whether std::vector's pop_back() throws or not. True, you don't see it. Practical answer: it's a nothrow operation. Practical thinking that relates to this, and applies to library writer: poping is cleanup and cleanup must not throw. I know of no implementation where that could throw, and would consider it implementation quality issue if it could. For example, do you know that pop_back in a vector never changes allocated storage? Downside of that is that once you reach some high-mark of elements, you don't never free. But the alternative is worse: if pop-back tried to reallocate, it would have a failure mode; we don't want that. > On the contrary, if we > look at the synopsis for boost::shared_ptr > (http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/shared_ptr.htm) > we see that most functions are documented with "// never throws" > How do we know that? Just because they write it? Or do they actually do > a try/catch(...) in the code, and if so, why not declare those functions > with throw()? Just because they write it. Doing a try/catch would be ludicrous from performance/code size point, and could also hide a bug in boost, however unlikely that might be. BTW, don't you trust e.g. standard lib/booost implementors to do the right thing? 'cause they do, much more often than I. Their code is better than mine if nothing else because there's so many eyes on their code, and so little on mine ;-). > > When you write "your job is to make sure it does not" (throw), I claim > that with the lack of documentation and compiler help, this is not an > easy task! That's strange. I claim that it is. Why do you think it is not? In fact, most of your trouble stems from this uneasy lack-of-safety- feeling of yours, doesn't it? I honestly don't have that feeling, and here's why: I find that nothrow pieces are __extremely__ rare in any code. And that's __EXTREMELY__. Because they are rare, not a lot of effort goes into making sure they stay nothrow, and one indeed needs to make a serious error to break that. Finally, due to their very nature (low level ops, cleanup), I find them easy to spot, too. > You also write "no-one in their right mind would put scope guard > creation in a function". I don't think I understand what you meant. I > would appreciate if you explained that. I was thinking: would you use scope guard if you had to do this all the time: ScopeGuard MakeGuardForX(...) throw() { return MakeGuard(...); } and then void f(...) { //... ScopeGuard g = MakeGuardForX(); //... } (that is, if you had to have a throw() function for every one of them?) I sure wouldn't. Goran. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: DeMarcus on 7 Feb 2010 16:12
> > Yes, that seems possible. Note, however that something innocuous like > std::string s("well now") might throw (bad_alloc is my favorite when > talking exceptions ;-)). Or, many calls to STL might throw. And > standard library does not use exception specification, nor do many > others. So one innocuous library call somewhere and your own spec > becomes invalid (think maintenance). (I guess there are reasons why > standard and other libraries don't use throw() and that this is > related to the spec of throw() and history.) > Maybe I'm slow but I still don't get it. According to the exception safety rules, a no-throw function like the destructor, pop, etc. must never throw. Then why on earth can't we put throw() on those functions since it's a run-time check anyway (and wouldn't break any current code)? >> Let's take a good example. Nowhere can I find proper documentation >> whether std::vector's pop_back() throws or not. > > True, you don't see it. Practical answer: it's a nothrow operation. > Practical thinking that relates to this, and applies to library > writer: poping is cleanup and cleanup must not throw. I know of no > implementation where that could throw, and would consider it > implementation quality issue if it could. For example, do you know > that pop_back in a vector never changes allocated storage? Downside of > that is that once you reach some high-mark of elements, you don't > never free. But the alternative is worse: if pop-back tried to > reallocate, it would have a failure mode; we don't want that. > You are right, but now you're talking out of experience. Not everyone has a vast experience, and it can still be difficult to guess whether a function is no-throw or not. What would you say about this function for instance? someonesFile.close(); It probably should be no-throw, but who knows what the inventor had in mind writing this File class? > > BTW, don't you trust e.g. standard lib/booost implementors to do the > right thing? 'cause they do, much more often than I. Their code is > better than mine if nothing else because there's so many eyes on their > code, and so little on mine ;-). > I trust the boost implementors fully, I mean, it was one of the founders of boost that published the idea of exception safety guarantees; the technique I'm now working hard to conform to. Nevertheless, just because they're renowned C++ experts, that doesn't stop me from proposing enhancements to their ideas. So if the following holds: * A no-throw function can, without functional harm, be declared throw() since such function must throw nothing, compared to a throw( MyException ) that can throw more than just MyException due to templates. If that holds, then I claim an optional feature in the compiler can, by means of static checking during compile-time, help finding no-throw functions that throws anyway. This optional feature would be no disadvantage, but only an enhancement helping programmers writing exception safe code. Please give your comments on this. Regards, Daniel -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |