
Hi, During the review of the string_algo library, there was a request for better specification of exception safety in the lib. I have put some info into the docs, but I'm not sure if it is correct and sufficient. Could some of you, that had lead the discussion about this topic (namely David Abrahams or David B. Held) check it out and tell me your opinion? I'm open to any suggestions. I want to make it reasonable and correct. I have written a general paragraph about the basic guarantee here: http://tinyurl.com/639ex and there are notes besides several algorithms like this: http://tinyurl.com/4yqp8 Thanks, Pavol

Pavol Droba wrote:
[...] I have put some info into the docs, but I'm not sure if it is correct and sufficient. Could some of you, that had lead the discussion about this topic (namely David Abrahams or David B. Held) check it out and tell me your opinion? [...]
Looks fine to me. However, instead of saying that the library makes assumptions about the exception safety of template and function arguments, I would say that providing the basic guarantee is a precondition for using the library. Also, I think it would be helpful to have a table of exactly which functions give a stronger guarantee, unless to_lower_copy() is the only such function, in which case you should just mention that in the original note. Note that it is operations which give exception safety guarantees, not types. For a given type, there may be functions (member or free) which offer the basic, strong or nothrow guarantee. Technically, you want to look at which member/user-defined functions of the argument types get called, and require those to provide the basic guarantee. Really, all functions should provide the basic guarantee, so this should really go without saying, but it's better to say it to remind users. This is probably how I would word that section: Exception Safety The library requires that all operations on types used as template or function arguments provide the basic guarantee. In turn, all functions and algorithms in this library, except where stated otherwise, will provide the basic guarantee. Now, here is where it gets tricky. You mention "const operations", which should probably read "pure operations", possibly with a note specifying that "pure" means "without side effects". But really, in order to provide the strong guarantee, you need to state exactly which user functions need to be pure. Let's analyze to_lower_copy() to see what we should say about it: template< typename ContainerT > inline ContainerT to_lower_copy( const ContainerT& Input, const std::locale& Loc=std::locale() ) { ContainerT Output; std::transform( string_algo::begin(Input), string_algo::end(Input), std::back_inserter<ContainerT>( Output ), string_algo::detail::to_lowerF(Loc) ); return Output; } Now, let's look at what functions are being called. First, std::locale() is called, but I'm pretty sure we can assume that does not modify global state. Thus, it is a pure function. Next, ContainerT() is called. If it provides the basic guarantee but modifies global state before throwing, then this function will not provide the strong guarantee. Next, string_algo::begin() and ::end() are called, which I assume are pure functions. Since std::back_inserter() is called on local data, it is pure with respect to to_lower_copy(). Since Loc is passed by const&, we assume that string_algo::detail::to_lowerF(Loc) does not modify Loc nor global state. Thus, it too is pure w.r.t. to_lower_copy(). Finally, since std::transform() is called on local or const data, it too is pure w.r.t. to_lower_copy(). So this function can give the strong guarantee if it has the signature { pure, strong, pure* } Where the first one is std::locale(), the second is ContainerT(), and the rest is std::transform et al. So what we really mean is that to_lower_copy() gives the strong guarantee when ContainerT's default constructor gives the strong guarantee. Note that none of the other c'tors of ContainerT need give any special guarantees. So be careful not to overspecify your client requirements for exception safety. Exception safety is a property of operations, not types. Hope that helps. Dave

David B. Held wrote:
[...] template< typename ContainerT > inline ContainerT to_lower_copy( const ContainerT& Input, const std::locale& Loc=std::locale() ) { ContainerT Output; std::transform( string_algo::begin(Input), string_algo::end(Input), std::back_inserter<ContainerT>( Output ), string_algo::detail::to_lowerF(Loc) );
return Output; } [...] So this function can give the strong guarantee if it has the signature
{ pure, strong, pure* } [...]
And here is where my analysis goes horribly wrong. First, this is not the signature of a strong function. This is: { pure*, strong!, nothrow* } But std::back_inserter() almost certainly does not give the nothrow guarantee, so something is wrong. Second, in order for to_lower_copy() to give the strong guarantee, ContainerT() must be a pure function w.r.t. to_lower_copy(). And it is, as long as it does not modify non-local data (global state). Once we add that condition, we get a function that is a sequence of pure operations, which *does* give the strong guarantee. So in the notes, you should really say: Notes: If SequenceT(void) does not modify global state, then the second variant of this function provides the strong exception safety guarantee. Dave

On Wed, Jul 14, 2004 at 07:55:23PM -0500, David B. Held wrote:
Pavol Droba wrote:
[...] I have put some info into the docs, but I'm not sure if it is correct and sufficient. Could some of you, that had lead the discussion about this topic (namely David Abrahams or David B. Held) check it out and tell me your opinion? [...]
Looks fine to me. However, instead of saying that the library makes assumptions about the exception safety of template and function arguments, I would say that providing the basic guarantee is a precondition for using the library. Also, I think it would be helpful to have a table of exactly which functions give a stronger guarantee, unless to_lower_copy() is the only such function, in which case you should just mention that in the original note. Note that it is operations which give exception safety guarantees, not types. For a given type, there may be functions (member or free) which offer the basic, strong or nothrow guarantee
You are correct. Exception guarantee should talk about the operations. Thats was what I originaly wanted to say ... but somehow it was lost in the translation. As for the table. It would be probably quite long. About 1/3-1/2 of functions are candidates for strong exception guarantie. There is not as each of them.
Technically, you want to look at which member/user-defined functions of the argument types get called, and require those to provide the basic guarantee. Really, all functions should provide the basic guarantee, so this should really go without saying, but it's better to say it to remind users. This is probably how I would word that section:
Exception Safety
The library requires that all operations on types used as template or function arguments provide the basic guarantee. In turn, all functions and algorithms in this library, except where stated otherwise, will provide the basic guarantee.
This seems reasonables. I my version I came from assuption, that user is not forced to provide any guarantee, on the other hand, she will not get more then she provides. But saying that as an explicit requirement is probably more consisten
Now, here is where it gets tricky. You mention "const operations", which should probably read "pure operations", possibly with a note specifying that "pure" means "without side effects".
Well difference between "pure" and "const" operations as I see it, is that const operations do not modify the state of the object, while pure operations do not modify global state as well. I wanted to close this gasp by requiring that const operations provide strong guarantee for the global state. Pure operations have strong guarantee by desing, but using this term will enforce me to specify which operations must be pure. And now I see, that I will need another type of operations to consider. Those that modify the internal state of an object, but do not touch the global state. So what I realy need it to specify is , that operations that are not closed to the object (i.e. they modify global state) have strong exception guarantie. Such a guarantee would allow me to use a local variable of a given type without needing to worry, that it will break the guarantie of the whole function. Is this ok? How would you name such a property?
But really, in order to provide the strong guarantee, you need to state exactly which user functions need to be pure. Let's analyze to_lower_copy() to see what we should say about it:
template< typename ContainerT > inline ContainerT to_lower_copy( const ContainerT& Input, const std::locale& Loc=std::locale() ) { ContainerT Output; std::transform( string_algo::begin(Input), string_algo::end(Input), std::back_inserter<ContainerT>( Output ), string_algo::detail::to_lowerF(Loc) );
return Output; }
Now, let's look at what functions are being called. First, std::locale() is called, but I'm pretty sure we can assume that does not modify global state. Thus, it is a pure function. Next, ContainerT() is called. If it provides the basic guarantee but modifies global state before throwing, then this function will not provide the strong guarantee.
I see that I have followed wrong assumption here. I forgot about the global state. I have assumed, that when a ContainerT() behaves nice (i.e have basic guarantee) and it is only a local object, that w.t.r to caller of the to_lower_copy it provides strong gurantie. Again you are right, I have to explicitly ask for preservation of global state.
Next, string_algo::begin() and ::end() are called, which I assume are pure functions. Since std::back_inserter() is called on local data, it is pure with respect to to_lower_copy(). Since Loc is passed by const&, we assume that string_algo::detail::to_lowerF(Loc) does not modify Loc nor global state. Thus, it too is pure w.r.t. to_lower_copy(). Finally, since std::transform() is called on local or const data, it too is pure w.r.t. to_lower_copy(). So this function can give the strong guarantee if it has the signature
{ pure, strong, pure* }
Where the first one is std::locale(), the second is ContainerT(), and the rest is std::transform et al. So what we really mean is that to_lower_copy() gives the strong guarantee when ContainerT's default constructor gives the strong guarantee. Note that none of the other c'tors of ContainerT need give any special guarantees. So be careful not to overspecify your client requirements for exception safety. Exception safety is a property of operations, not types. Hope that helps.
Thanks for help. I see, that I'm on the right track, but there is still some work to be done. Regards, Pavol

Pavol Droba <droba@topmail.sk> writes:
Such a guarantee would allow me to use a local variable of a given type without needing to worry, that it will break the guarantie of the whole function.
Is this ok?
How would you name such a property?
While I support the use of the "pure" distinction in exception-safety analysis, a word of caution: be careful not to specify such a detailed ES contract that it becomes unreasonably hard to use. Another risk is that you'll undly constrain your future implementation choices. Sometimes it makes sense to paint with a slightly broader brush and and provide a simpler guarantee. Further, I'm not sure it usually makes sense to use "pure" when describing constraints on user-supplied operations. It stands to reason that in general, the library has no knowledge of external state that might be modified by a user-supplied operation and can't roll back the results. It's often a reasonable shorthand to say "gives the strong guarantee" when you mean "gives the strong guarantee as long as the user-supplied operation is pure". -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

On Thu, Jul 15, 2004 at 07:03:38AM -0400, David Abrahams wrote:
Pavol Droba <droba@topmail.sk> writes:
Such a guarantee would allow me to use a local variable of a given type without needing to worry, that it will break the guarantie of the whole function.
Is this ok?
How would you name such a property?
While I support the use of the "pure" distinction in exception-safety analysis, a word of caution: be careful not to specify such a detailed ES contract that it becomes unreasonably hard to use. Another risk is that you'll undly constrain your future implementation choices. Sometimes it makes sense to paint with a slightly broader brush and and provide a simpler guarantee.
Further, I'm not sure it usually makes sense to use "pure" when describing constraints on user-supplied operations. It stands to reason that in general, the library has no knowledge of external state that might be modified by a user-supplied operation and can't roll back the results. It's often a reasonable shorthand to say "gives the strong guarantee" when you mean "gives the strong guarantee as long as the user-supplied operation is pure".
What I want to cover is quite a large number of algorithms in the lib, that can supply strong guagantee if - const operations are pure - all operations for a specific type, change only the object itself and not the global state (or at least, they give a strong guarantee when they do) IMHO this is very natural behaviour for most of the containers. To say it in plain words, I want algorithm, that change only local variables and use const inputs to have strong guarantee if the inputs behave well. I think that this is reasonable, but I'm not sure how to correctly formulate the specification. Regards, Pavol

Pavol Droba <droba@topmail.sk> writes:
On Thu, Jul 15, 2004 at 07:03:38AM -0400, David Abrahams wrote:
Pavol Droba <droba@topmail.sk> writes:
Such a guarantee would allow me to use a local variable of a given type without needing to worry, that it will break the guarantie of the whole function.
Is this ok?
How would you name such a property?
While I support the use of the "pure" distinction in exception-safety analysis, a word of caution: be careful not to specify such a detailed ES contract that it becomes unreasonably hard to use. Another risk is that you'll undly constrain your future implementation choices. Sometimes it makes sense to paint with a slightly broader brush and and provide a simpler guarantee.
Further, I'm not sure it usually makes sense to use "pure" when describing constraints on user-supplied operations. It stands to reason that in general, the library has no knowledge of external state that might be modified by a user-supplied operation and can't roll back the results. It's often a reasonable shorthand to say "gives the strong guarantee" when you mean "gives the strong guarantee as long as the user-supplied operation is pure".
What I want to cover is quite a large number of algorithms in the lib, that can supply strong guagantee if - const operations are pure
I still don't know what a const operation is. The power of good distinctions is in their simplicity; let's try not to add too many new terms.
- all operations for a specific type, change only the object itself and not the global state (or at least, they give a strong guarantee when they do)
That's just the strong guarantee; no need to complicate terminology. Consider the language precedent set in the standard: "If an exception is thrown, there are no effects other than those of <user-supplied operation>" and "If an exception is thrown other than by <user-supplied operation>, there are no effects"
IMHO this is very natural behaviour for most of the containers.
To say it in plain words, I want algorithm, that change only local variables and use const inputs to have strong guarantee if the inputs behave well.
I don't understand the above; it sounds like a design criterion but IIUC your code is already written and you're just trying to document it. Nobody cares (at this point) what you're doing inside your function with local variables and inputs, so I think talking about that stuff is heading in the wrong direciton.
I think that this is reasonable, but I'm not sure how to correctly formulate the specification.
-- Dave Abrahams Boost Consulting http://www.boost-consulting.com

On Thu, Jul 15, 2004 at 08:40:03AM -0400, David Abrahams wrote:
Pavol Droba <droba@topmail.sk> writes:
On Thu, Jul 15, 2004 at 07:03:38AM -0400, David Abrahams wrote:
Pavol Droba <droba@topmail.sk> writes:
Such a guarantee would allow me to use a local variable of a given type without needing to worry, that it will break the guarantie of the whole function.
Is this ok?
How would you name such a property?
While I support the use of the "pure" distinction in exception-safety analysis, a word of caution: be careful not to specify such a detailed ES contract that it becomes unreasonably hard to use. Another risk is that you'll undly constrain your future implementation choices. Sometimes it makes sense to paint with a slightly broader brush and and provide a simpler guarantee.
Further, I'm not sure it usually makes sense to use "pure" when describing constraints on user-supplied operations. It stands to reason that in general, the library has no knowledge of external state that might be modified by a user-supplied operation and can't roll back the results. It's often a reasonable shorthand to say "gives the strong guarantee" when you mean "gives the strong guarantee as long as the user-supplied operation is pure".
What I want to cover is quite a large number of algorithms in the lib, that can supply strong guagantee if - const operations are pure
I still don't know what a const operation is. The power of good distinctions is in their simplicity; let's try not to add too many new terms.
I see. Under the term "const operation" I understand an operation that does not alfter the state of the associated objects. Examples are const member functions.
- all operations for a specific type, change only the object itself and not the global state (or at least, they give a strong guarantee when they do)
That's just the strong guarantee; no need to complicate terminology.
Consider the language precedent set in the standard:
"If an exception is thrown, there are no effects other than those of <user-supplied operation>"
and
"If an exception is thrown other than by <user-supplied operation>, there are no effects"
Ok. I was confused, because I was always talking about this kind of guarantee, but everytime, somebody corrected me, that I forgot about the global state. So I wanted to be precise.
IMHO this is very natural behaviour for most of the containers.
To say it in plain words, I want algorithm, that change only local variables and use const inputs to have strong guarantee if the inputs behave well.
I don't understand the above; it sounds like a design criterion but IIUC your code is already written and you're just trying to document it. Nobody cares (at this point) what you're doing inside your function with local variables and inputs, so I think talking about that stuff is heading in the wrong direciton.
No, I wanted to formulate a specification for the class of algorithms, that I have described. Now I see, that plain formulation "they provide strong exception guarantee" is enough. And that is exactly the point I wanted to get to. Regards, Pavol

Pavol Droba <droba@topmail.sk> writes:
Now I see, that plain formulation "they provide strong exception guarantee" is enough. And that is exactly the point I wanted to get to.
I strongly believe that the language "if an exception is thrown there are no effects" is better than talking about the strong guarantee, because eventually you get into variations like these:
"If an exception is thrown, there are no effects other than those of <user-supplied operation>"
and
"If an exception is thrown other than by <user-supplied operation>, there are no effects"
and the basic language used is the same. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote in message news:uy8ll2rhr.fsf@boost-consulting.com... | Pavol Droba <droba@topmail.sk> writes: | | > Now I see, that plain formulation "they provide strong exception guarantee" | > is enough. And that is exactly the point I wanted to get to. | | I strongly believe that the language "if an exception is thrown there | are no effects" is better than talking about the strong guarantee, | because eventually you get into variations like these: | | > "If an exception is thrown, there are no effects other than those | > of <user-supplied operation>" | > | > and | > | > "If an exception is thrown other than by <user-supplied operation>, | > there are no effects" | | and the basic language used is the same. I don't quite see that. I believe a concise terminology is better than plain laguage. The plain language can be used to explain the term, but moving awau from a terminology is a step in the wrong direction. So I would support "basic guarantee", "strong guarantee" and "nothrow guarantee" terms. br Thorsten

On Thu, Jul 15, 2004 at 07:03:38AM -0400, David Abrahams wrote:
Pavol Droba <droba@topmail.sk> writes:
Such a guarantee would allow me to use a local variable of a given type without needing to worry, that it will break the guarantie of the whole function.
Is this ok?
How would you name such a property?
While I support the use of the "pure" distinction in exception-safety analysis, a word of caution: be careful not to specify such a detailed ES contract that it becomes unreasonably hard to use. Another risk is that you'll undly constrain your future implementation choices. Sometimes it makes sense to paint with a slightly broader brush and and provide a simpler guarantee.
Further, I'm not sure it usually makes sense to use "pure" when describing constraints on user-supplied operations. It stands to reason that in general, the library has no knowledge of external state that might be modified by a user-supplied operation and can't roll back the results. It's often a reasonable shorthand to say "gives the strong guarantee" when you mean "gives the strong guarantee as long as the user-supplied operation is pure".
I have written sumarized something. Is this correct: " Exception Safety The library requires that all operations on types used as template or function arguments provide the basic exception guarantee. In turn, all functions and algorithms in this library, except where stated otherwise, will provide the basic exceptions guarantee. In addtion some functions can provide the strong exception guarantee as long as the operations on the types used for arguments for these funtions either do not alter the global state, or provide the strong exception guarantee. " Pavol

Pavol Droba <droba@topmail.sk> writes:
On Thu, Jul 15, 2004 at 07:03:38AM -0400, David Abrahams wrote:
Pavol Droba <droba@topmail.sk> writes:
Such a guarantee would allow me to use a local variable of a given type without needing to worry, that it will break the guarantie of the whole function.
Is this ok?
How would you name such a property?
While I support the use of the "pure" distinction in exception-safety analysis, a word of caution: be careful not to specify such a detailed ES contract that it becomes unreasonably hard to use. Another risk is that you'll undly constrain your future implementation choices. Sometimes it makes sense to paint with a slightly broader brush and and provide a simpler guarantee.
Further, I'm not sure it usually makes sense to use "pure" when describing constraints on user-supplied operations. It stands to reason that in general, the library has no knowledge of external state that might be modified by a user-supplied operation and can't roll back the results. It's often a reasonable shorthand to say "gives the strong guarantee" when you mean "gives the strong guarantee as long as the user-supplied operation is pure".
I have written sumarized something. Is this correct:
" Exception Safety
The library requires that all operations on types used as template or function arguments provide the basic exception guarantee. In turn, all functions and algorithms in this library, except where stated otherwise, will provide the basic exceptions guarantee.
I hope not. There should be no instance in which you don't provide the basic guarantee. Fundamentally you don't have to say any of what's in that paragraph, though I don't mind it in principle. By definition, you *can't* break invariants. Unless you explicitly say you're going to leak resources, the client has a right to expect you won't, even in the face of exceptions. Nothing gives the client license to break imposed requirements, even in the face of exceptions.
In addtion some functions can provide the strong exception guarantee as long as the operations on the types used for arguments for these funtions either do not alter the global state, or provide the strong exception guarantee.
Probably an English usage error, but that means that if operations on the arguments to functions provide the strong guarantee, the functions won't provide it. I would either throw out this whole thing or rewrite it as follows: The library maintains its invariants and does not leak resources in the face of exceptions. Some library operations give stronger guarantees, which are documented on an individual basis. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
Pavol Droba <droba@topmail.sk> writes: [...]
" Exception Safety
The library requires that all operations on types used as template or function arguments provide the basic exception guarantee. In turn, all functions and algorithms in this library, except where stated otherwise, will provide the basic exceptions guarantee.
I hope not. There should be no instance in which you don't provide the basic guarantee.
The idea is that the library may offer some other guarantee instead of the basic guarantee.
Fundamentally you don't have to say any of what's in that paragraph, though I don't mind it in principle. By definition, you *can't* break invariants. Unless you explicitly say you're going to leak resources, the client has a right to expect you won't, even in the face of exceptions. Nothing gives the client license to break imposed requirements, even in the face of exceptions.
Well, considering that many programmers don't even know how to talk about exception safety, I don't think it hurts to have a reminder that if the library behaves in an exception-unsafe way, it's the user's fault.
[...] I would either throw out this whole thing or rewrite it as follows:
The library maintains its invariants and does not leak resources in the face of exceptions. Some library operations give stronger guarantees, which are documented on an individual basis.
Ah, but you yourself have said that the guarantees do not form a hierarchy, so there is no proper notion of "stronger" with respect to them. ;) Pretty easy to say it that way though, huh? Anyway, I would say that many libraries do *not* offer the basic guarantee, and that the value in saying so is that it indicates the author has considered the issue and certifies that the library is minimally exception-safe. Saying that it maintains its invariants instead of saying that it gives the basic guarantee does not convey the right message, in my opinion, because many programmers obviously do not feel a need to maintain invariants in the presence of exceptions (or they would write more exception-safe code). Dave

"David B. Held" <dheld@codelogicconsulting.com> writes:
David Abrahams wrote:
" Exception Safety
The library requires that all operations on types used as template or function arguments provide the basic exception guarantee. In turn, all functions and algorithms in this library, except where stated otherwise, will provide the basic exceptions guarantee. I hope not. There should be no instance in which you don't provide
Pavol Droba <droba@topmail.sk> writes: [...] the basic guarantee.
The idea is that the library may offer some other guarantee instead of the basic guarantee.
No, you can strengthen the guarantee -- in other words, offer some guarantees in addition to the basic guarantee -- but unless the library is going to take an "invariants don't matter because I'm about to terminate" strategy, you must always give the basic guarantee.
Fundamentally you don't have to say any of what's in that paragraph, though I don't mind it in principle. By definition, you *can't* break invariants. Unless you explicitly say you're going to leak resources, the client has a right to expect you won't, even in the face of exceptions. Nothing gives the client license to break imposed requirements, even in the face of exceptions.
Well, considering that many programmers don't even know how to talk about exception safety, I don't think it hurts to have a reminder that if the library behaves in an exception-unsafe way, it's the user's fault.
I agree that a reminder is good, but don't agree with "if the library behaves in an exception-unsafe way", because it's not the library that's misbehaving.
[...] I would either throw out this whole thing or rewrite it as follows: The library maintains its invariants and does not leak resources in the face of exceptions. Some library operations give stronger guarantees, which are documented on an individual basis.
Ah, but you yourself have said that the guarantees do not form a hierarchy, so there is no proper notion of "stronger" with respect to them. ;)
Whaaaa??? I never said that! Or I was delusional when I did.
Pretty easy to say it that way though, huh? Anyway, I would say that many libraries do *not* offer the basic guarantee, and that the value in saying so is that it indicates the author has considered the issue and certifies that the library is minimally exception-safe.
Yes, but if the reader doesn't know the meaning of the term, it will not help her. It's such a simple concept that it doesn't hurt to spell it out.
Saying that it maintains its invariants instead of saying that it gives the basic guarantee does not convey the right message, in my opinion, because many programmers obviously do not feel a need to maintain invariants in the presence of exceptions (or they would write more exception-safe code).
I don't see the connection. What message do you think it should send that it does not send? -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
[...]
Ah, but you yourself have said that the guarantees do not form a hierarchy, so there is no proper notion of "stronger" with respect to them. ;)
Whaaaa??? I never said that! Or I was delusional when I did.
Well, perhaps you remember a thread in which I suggested another guarantee that I called the "smart guarantee" which was a cross between the strong and the basic guarantee. You argued that one could invent any number of guarantees that offer different promises and which could not be ordered in any purely objective way. It was a fairly convincing argument at the time. Are you going to retract it? ;>
[...]
Saying that it maintains its invariants instead of saying that it gives the basic guarantee does not convey the right message, in my opinion, because many programmers obviously do not feel a need to maintain invariants in the presence of exceptions (or they would write more exception-safe code).
I don't see the connection. What message do you think it should send that it does not send?
That it maintains invariants *in the presence of exceptions*. The latter part is implicit, but if the user isn't thinking in terms of exception safety to begin with, then they may well miss that part. When you say "provides the basic guarantee", if the user is not familiar with exception safety, she will at least have an opportunity to investigate it. Of course, you could just say both. Dave

"David B. Held" <dheld@codelogicconsulting.com> writes:
David Abrahams wrote:
[...]
Ah, but you yourself have said that the guarantees do not form a hierarchy, so there is no proper notion of "stronger" with respect ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ to them. ;) ^^^^^^^^ Whaaaa??? I never said that! Or I was delusional when I did.
Well, perhaps you remember a thread in which I suggested another guarantee that I called the "smart guarantee" which was a cross between the strong and the basic guarantee. You argued that one could invent any number of guarantees that offer different promises and which could not be ordered in any purely objective way. It was a fairly convincing argument at the time. Are you going to retract it? ;>
Not at all. But I never said the marked thing above. Certainly any guarantee that only adds requirements to another is stronger. It's a partial order. There are plenty of pairs of guarantees that have an ordering relationship, and plenty of others that don't.
Saying that it maintains its invariants instead of saying that it gives the basic guarantee does not convey the right message, in my opinion, because many programmers obviously do not feel a need to maintain invariants in the presence of exceptions (or they would write more exception-safe code). I don't see the connection. What message do you think it should send
[...] that it does not send?
That it maintains invariants *in the presence of exceptions*.
Quoting my original suggestion:
... The library maintains its invariants and does not leak resources in the face of exceptions. Some library operations give stronger ^^^^^^^^^^^^^^^^^^^^^^^^^ ...
Perhaps we have an "and" associativity/ambiguity problem here? It meant the same as this when I wrote it: ;-) In the face of exceptions, the library maintains its invariants and does not leak resources.
The latter part is implicit, but if the user isn't thinking in terms of exception safety to begin with, then they may well miss that part. When you say "provides the basic guarantee", if the user is not familiar with exception safety, she will at least have an opportunity to investigate it. Of course, you could just say both.
Which is what I suggested in another message. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
[...] Further, I'm not sure it usually makes sense to use "pure" when describing constraints on user-supplied operations. It stands to reason that in general, the library has no knowledge of external state that might be modified by a user-supplied operation and can't roll back the results. It's often a reasonable shorthand to say "gives the strong guarantee" when you mean "gives the strong guarantee as long as the user-supplied operation is pure".
But what is the user-supplied operation, and how does the user know she has supplied it? In this case, it's the default c'tor for the Sequence, but the function is not documented as taking that as a user-spplied operation. Thus, it seems worthwhile to tell the user which operations must be pure in order to get the strong guarantee. Will that constrain implementations? Maybe. But safety isn't free. The only alternative I see is to not even attempt to offer the strong guarantee. Dave

"David B. Held" <dheld@codelogicconsulting.com> writes:
David Abrahams wrote:
[...] Further, I'm not sure it usually makes sense to use "pure" when describing constraints on user-supplied operations. It stands to reason that in general, the library has no knowledge of external state that might be modified by a user-supplied operation and can't roll back the results. It's often a reasonable shorthand to say "gives the strong guarantee" when you mean "gives the strong guarantee as long as the user-supplied operation is pure".
But what is the user-supplied operation, and how does the user know she has supplied it?
There's no mystery. The algorithm spells out its requirements on its type arguments. Part of those requirements has to include the operations that the algorithm will perform on those arguments.
In this case, it's the default c'tor for the Sequence, but the function is not documented as taking that as a user-spplied operation.
The function had better darned well document that it requires Sequence to satisfy certain concept requirements that include default-constructibility (and maybe push_back or whatever the operation needs).
Thus, it seems worthwhile to tell the user which operations must be pure in order to get the strong guarantee. Will that constrain implementations? Maybe. But safety isn't free. The only alternative I see is to not even attempt to offer the strong guarantee.
No, you just follow the established practice for documenting exception-safety in generic functions. There's no need to reinvent the wheel. I think purity is a useful idea for analyzing exception safety, and I have no objection to mentioning it in specifications _if_ it truly adds clarity. If the specification can be considered minimal and complete without mentioning purity, that might be better. It might be best to describe what it means to say "has no effects" in one place. Maybe I should put a section in http://www.boost.org/more/error_handling.html that discusses these conventions for documenting exception-safety. Then library documentation can link to that part of the page. It would say something like: - Unless otherwise specified, all Boost library operations give the /basic guarantee/: the library's maintains its invariants and does not leak resources in the face of exceptions. - Some library operations give the /strong guarantee/ that if an exception is thrown, there are no effects. If those operations involve calls to user-supplied operations (such as copying an instance of a template type parameter) and those operations have side-effects, it's understood that those side-effects are outside the control of the library and not included in the strong guarantee. - ...anything else...? Then I would probably add a section that showed some examples of the kind of language used to document exception-safety, and describe how to understand it. Thoughts? -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
[...] It might be best to describe what it means to say "has no effects" in one place. Maybe I should put a section in http://www.boost.org/more/error_handling.html that discusses these conventions for documenting exception-safety. Then library documentation can link to that part of the page. It would say something like:
- Unless otherwise specified, all Boost library operations give the /basic guarantee/: the library's maintains its invariants and does not leak resources in the face of exceptions.
I would just make the editorial fixes as so: ...the library maintains its invariants...
- Some library operations give the /strong guarantee/ that if an exception is thrown, there are no effects. If those operations involve calls to user-supplied operations (such as copying an instance of a template type parameter) and those operations have side-effects, it's understood that those side-effects are outside the control of the library and not included in the strong guarantee.
Looks good.
- ...anything else...?
Then I would probably add a section that showed some examples of the kind of language used to document exception-safety, and describe how to understand it.
Thoughts?
I think it's a good idea overall, and perhaps some older libraries that don't document exception safety should revisit the issue. The library requirements page mentions "Discussion of error detection and recovery strategy", but doesn't require any particular section to be in the documentation. Perhaps we should require that libraries that offer something other than the basic guarantee include an exception safety section in the docs. Dave

"David B. Held" <dheld@codelogicconsulting.com> writes:
something like: - Unless otherwise specified, all Boost library operations give the /basic guarantee/: the library's maintains its invariants and does not leak resources in the face of exceptions.
I would just make the editorial fixes as so:
...the library maintains its invariants...
I don't understand what you're suggesting. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

"David B. Held" <dheld@codelogicconsulting.com> writes:
David Abrahams wrote:
[...] It might be best to describe what it means to say "has no effects" in one place. Maybe I should put a section in http://www.boost.org/more/error_handling.html that discusses these conventions for documenting exception-safety. Then library documentation can link to that part of the page. It would say something like: - Unless otherwise specified, all Boost library operations give the /basic guarantee/: the library's maintains its invariants and does not leak resources in the face of exceptions.
I would just make the editorial fixes as so:
...the library maintains its invariants...
I don't understand what you're suggesting here. Can you be more explicit? -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
"David B. Held" <dheld@codelogicconsulting.com> writes:
David Abrahams wrote:
[...] - Unless otherwise specified, all Boost library operations give the /basic guarantee/: the library's maintains its invariants and does
not leak resources in the face of exceptions.
I would just make the editorial fixes as so:
...the library maintains its invariants...
I don't understand what you're suggesting here. Can you be more explicit?
It's a trivial matter of grammar. You wrote "...the library's maintains...", which has improper subject-verb agreement (number). In fact, you probably din't mean to use the posessive case at all, which is what I changed. Dave

"David B. Held" <dheld@codelogicconsulting.com> writes:
David Abrahams wrote:
"David B. Held" <dheld@codelogicconsulting.com> writes:
David Abrahams wrote:
[...] - Unless otherwise specified, all Boost library operations give the /basic guarantee/: the library's maintains its invariants and does
not leak resources in the face of exceptions.
I would just make the editorial fixes as so:
...the library maintains its invariants... I don't understand what you're suggesting here. Can you be more explicit?
It's a trivial matter of grammar. You wrote "...the library's maintains...", which has improper subject-verb agreement (number). In fact, you probably din't mean to use the posessive case at all, which is what I changed.
Thanks. I missed it the first time, and then I missed it when you corrected it! -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

Hi, On Sat, Jul 17, 2004 at 08:31:07AM -0400, David Abrahams wrote: [snip]
No, you just follow the established practice for documenting exception-safety in generic functions. There's no need to reinvent the wheel.
I think purity is a useful idea for analyzing exception safety, and I have no objection to mentioning it in specifications _if_ it truly adds clarity. If the specification can be considered minimal and complete without mentioning purity, that might be better.
It might be best to describe what it means to say "has no effects" in one place. Maybe I should put a section in http://www.boost.org/more/error_handling.html that discusses these conventions for documenting exception-safety. Then library documentation can link to that part of the page. It would say something like:
- Unless otherwise specified, all Boost library operations give the /basic guarantee/: the library's maintains its invariants and does not leak resources in the face of exceptions.
- Some library operations give the /strong guarantee/ that if an exception is thrown, there are no effects. If those operations involve calls to user-supplied operations (such as copying an instance of a template type parameter) and those operations have side-effects, it's understood that those side-effects are outside the control of the library and not included in the strong guarantee.
- ...anything else...?
Then I would probably add a section that showed some examples of the kind of language used to document exception-safety, and describe how to understand it.
Thoughts?
For me, this seems rather fine. I have tried to sumarize something similar in <http://tinyurl.com/3wgvu>. I thinks, that overspecification is not very useful. Detailed definition what operations are reguired to have which guarantee for each function is nice for library correctness checking, but not for an average user. Regards, Pavol

Pavol Droba <droba@topmail.sk> writes:
For me, this seems rather fine. I have tried to sumarize something similar in <http://tinyurl.com/3wgvu>.
The "defintion" of the strong guarantee here is just wrong: Some functions can provide the strong exception-safety guarantee. That means that following statements are true: If an exception is thrown, there are no effects other than those of the function ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ I don't mean to pick on you, Pavol, but I don't understand why this keeps happening: people seem unsatisfied with my original wording and make changes that alter the meaning. In fact, the statement that a function has "no effects other than those of the function" is a meaningless tautology. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

On Fri, Jul 30, 2004 at 07:04:13AM -0700, David Abrahams wrote:
Pavol Droba <droba@topmail.sk> writes:
For me, this seems rather fine. I have tried to sumarize something similar in <http://tinyurl.com/3wgvu>.
The "defintion" of the strong guarantee here is just wrong:
Some functions can provide the strong exception-safety guarantee. That means that following statements are true:
If an exception is thrown, there are no effects other than those of the function ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I don't mean to pick on you, Pavol, but I don't understand why this keeps happening: people seem unsatisfied with my original wording and make changes that alter the meaning. In fact, the statement that a function has "no effects other than those of the function" is a meaningless tautology.
I don't want to argue, since little bit lost in the discussion. The wording, that can be seen in the documentation, is my attempt to sumarize the discussion that was happening before I left to holidays. During the time I was away, the discussion continued and you have suggested more precise wording. Actualy I will be more then happy to copy-paste a paragraph rather than to reinvent a wheel (most likely broken) on my own. So will it be ok if I copy your definition from here: <http://article.gmane.org/gmane.comp.lib.boost.devel/105915> ? Regards, Pavol

Pavol Droba <droba@topmail.sk> writes:
So will it be ok if I copy your definition from here: <http://article.gmane.org/gmane.comp.lib.boost.devel/105915>
You may, but I would prefer to update http://www.boost.org/more/error_handling.html and for you to post a link to that material. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

On Fri, Jul 30, 2004 at 09:19:47AM -0700, David Abrahams wrote:
Pavol Droba <droba@topmail.sk> writes:
So will it be ok if I copy your definition from here: <http://article.gmane.org/gmane.comp.lib.boost.devel/105915>
You may, but I would prefer to update http://www.boost.org/more/error_handling.html and for you to post a link to that material.
Don't you mean <http://www.boost.org/more/generic_exception_safety.html> ? I have a link to this page already. Pavol

Pavol Droba <droba@topmail.sk> writes:
On Fri, Jul 30, 2004 at 09:19:47AM -0700, David Abrahams wrote:
Pavol Droba <droba@topmail.sk> writes:
So will it be ok if I copy your definition from here: <http://article.gmane.org/gmane.comp.lib.boost.devel/105915>
You may, but I would prefer to update http://www.boost.org/more/error_handling.html and for you to post a link to that material.
Don't you mean <http://www.boost.org/more/generic_exception_safety.html> ?
No I do not. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

On Fri, Jul 30, 2004 at 02:07:05PM -0600, David Abrahams wrote:
Pavol Droba <droba@topmail.sk> writes:
On Fri, Jul 30, 2004 at 09:19:47AM -0700, David Abrahams wrote:
Pavol Droba <droba@topmail.sk> writes:
So will it be ok if I copy your definition from here: <http://article.gmane.org/gmane.comp.lib.boost.devel/105915>
You may, but I would prefer to update http://www.boost.org/more/error_handling.html and for you to post a link to that material.
Don't you mean <http://www.boost.org/more/generic_exception_safety.html> ?
No I do not.
Ok, but I don't get it. The article you are refering is gereneraly describing how to desing exceptions classe and how to throw an exception. There is nothing even a marginaly close to an exception guarantie specification. I assume, that this is what you want to add here. But don't you think, that this is little bit unrelated to current problem? AFAIK, we are trying to define a specification for a library. This specification is primary oriented towards a user of the library, while this article is a collection of good principles for a library authors. In my understanding we need a proper definition of the exception safety concepts what can be later used to label operations in the library. From the discussion it seems, that conditional concepts should be defined, or the current concepts should be made conditional by default. So I think, that we need a shorter version of generic-exception-safety document rather then hide this information inside an unrelated doc. I might have overlooked something. So please explain your rationale. Regards, Pavol

Pavol Droba <droba@topmail.sk> writes:
Hi,
During the review of the string_algo library, there was a request for better specification of exception safety in the lib.
I have put some info into the docs, but I'm not sure if it is correct and sufficient. Could some of you, that had lead the discussion about this topic (namely David Abrahams or David B. Held) check it out and tell me your opinion? I'm open to any suggestions. I want to make it reasonable and correct.
I have written a general paragraph about the basic guarantee here:
Should probably link to http://www.boost.org/more/generic_exception_safety.html there.
and there are notes besides several algorithms like this: http://tinyurl.com/4yqp8
I don't know if you did something special or if it's BoostBook convention, but the code font is unreadably small in FireFox when I look at it with normal settings. template<typename OutputIteratorT, typename CollectionT> OutputIteratorT to_lower_copy(OutputIteratorT Output, const CollectionT & Input, const std::locale & Loc = std::locale()); template<typename SequenceT> SequenceT to_lower_copy(const SequenceT & Input, const std::locale & Loc = std::locale()); Notes: If the input parameters satisfy the second assumption about exception safety, second variant of this function provides strong exception guarantee. This is way too indirect. What's "the second assumption about exception safety"? It's fair game to: 1. Explain in one place what it means to read elements from an input sequence and create a new sequence and copy elements to it, and 2. Just say that to_lower_copy gives the strong guarantee, with the understanding that the algorithm has no control over what the input sequence does and so any side effects it causes are outside what's described by these requirements. That's the basic tack taken by the standard. No, it doesn't spell everything out in agonizing detail for each function. On the other hand, the specification is understandable, and actually is very explicit unless user-supplied operations have very unusual behaviors. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
[...] It's fair game to:
1. Explain in one place what it means to read elements from an input sequence and create a new sequence and copy elements to it, and
2. Just say that to_lower_copy gives the strong guarantee, with the understanding that the algorithm has no control over what the input sequence does and so any side effects it causes are outside what's described by these requirements.
That's the basic tack taken by the standard. No, it doesn't spell everything out in agonizing detail for each function. On the other hand, the specification is understandable, and actually is very explicit unless user-supplied operations have very unusual behaviors.
If all the functions which offer the strong guarantee have the same form of creating a local and operating on that, then I agree that a central explanation is probably best. I'm a little dissatisfied with 2, because it implies that using something like an istream iterator will no longer give you the strong guarantee, but it doesn't come right out and say so. Probably nobody will assume beforehand that anything else would be the case, but it seems that it would be more clear just to say that if your iterators or c'tors have side effects, then you no longer get any guarantees at all. Dave

"David B. Held" <dheld@codelogicconsulting.com> writes:
David Abrahams wrote:
[...] It's fair game to: 1. Explain in one place what it means to read elements from an input sequence and create a new sequence and copy elements to it, and 2. Just say that to_lower_copy gives the strong guarantee, with the understanding that the algorithm has no control over what the input sequence does and so any side effects it causes are outside what's described by these requirements.
Just to be clear, these are not alternatives; they're meant to be done together.
That's the basic tack taken by the standard. No, it doesn't spell everything out in agonizing detail for each function. On the other hand, the specification is understandable, and actually is very explicit unless user-supplied operations have very unusual behaviors.
If all the functions which offer the strong guarantee have the same form of creating a local and operating on that
The internal form of the documented functions is irrelevant. It's their external behavior that matters.
then I agree that a central explanation is probably best. I'm a little dissatisfied with 2, because it implies that using something like an istream iterator will no longer give you the strong guarantee, but it doesn't come right out and say so.
Yes. It's the strong guarantee "within the scope of control of the algorithm".
Probably nobody will assume beforehand that anything else would be the case, but it seems that it would be more clear just to say that if your iterators or c'tors have side effects, then you no longer get any guarantees at all.
Very bad idea. There's no reason that the algorithm should give up the basic guarantee in that case. Consider: template <class InputIterator> std::vector::assign(InputIterator,InputIterator) That really gives the basic guarantee with no hidden assumptions. Now suppose we had written std::vector::assign with copy/swap internally (it doesn't work that way, but just for the sake of argument). It's much more useful to say that it gives the strong guarantee with the understanding that InputIterator's side effects are out of the algorithm's control than it is to give up all guarantees if InputIterator has side-effects. In case you think this is an "evil glossing over of detail", there are actually lots of these assumptions lurking in standard requirements, but they still work very well. For example, if incrementing InputIterator actually had the side-effect of modifying the vector, how well do you think std::vector::assign would work? How understandable do you think the specification would be if all these kinds of details were actually spelled out? -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
[...] Very bad idea. There's no reason that the algorithm should give up the basic guarantee in that case. Consider:
template <class InputIterator> std::vector::assign(InputIterator,InputIterator)
That really gives the basic guarantee with no hidden assumptions.
It assumes that there are no invariants that require, for instance, that all the input is consumed.
[...] In case you think this is an "evil glossing over of detail",
I wouldn't call it "evil"...
there are actually lots of these assumptions lurking in standard requirements, but they still work very well. For example, if incrementing InputIterator actually had the side-effect of modifying the vector, how well do you think std::vector::assign would work? How understandable do you think the specification would be if all these kinds of details were actually spelled out?
...but I guess it's the difference between a theorist and an engineer. As a little of both, I would like to simultaneously argue for rigor and pragmatism. ;) Dave

"David B. Held" <dheld@codelogicconsulting.com> writes:
David Abrahams wrote:
[...] Very bad idea. There's no reason that the algorithm should give up the basic guarantee in that case. Consider: template <class InputIterator> std::vector::assign(InputIterator,InputIterator) That really gives the basic guarantee with no hidden assumptions.
It assumes that there are no invariants that require, for instance, that all the input is consumed.
I hate to <sigh> because it's rude, but... <sigh>. I don't know how to explain this any better. You have to make a distinction between layers of a system or you couldn't give sensible guarantees for anything. Your policy_ptr can never call operator new if it's been replaced and the whole program has an invariant that it is never called more than some fixed number of times. But of course your policy_ptr can't know anything about the whole program invariants, so it can make guarantees at its level of influence and knowledge.
[...] In case you think this is an "evil glossing over of detail",
I wouldn't call it "evil"...
there are actually lots of these assumptions lurking in standard requirements, but they still work very well. For example, if incrementing InputIterator actually had the side-effect of modifying the vector, how well do you think std::vector::assign would work? How understandable do you think the specification would be if all these kinds of details were actually spelled out?
...but I guess it's the difference between a theorist and an engineer. As a little of both, I would like to simultaneously argue for rigor and pragmatism. ;)
Fine, let's factor the niggly stuff needed to make the specification rigorous out and put it in one place, rather than sprinkling it through the documentation of each function. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
[...] You have to make a distinction between layers of a system or you couldn't give sensible guarantees for anything. Your policy_ptr can never call operator new if it's been replaced and the whole program has an invariant that it is never called more than some fixed number of times. But of course your policy_ptr can't know anything about the whole program invariants, so it can make guarantees at its level of influence and knowledge. [...]
And yet, the question is how much of a library's implementation should be exposed/documented so that the user knows what they are affecting when they make globally intrusive changes? I'm not suggesting that a library should be responsible for things outside of its control. I'm saying that we have an issue of unavoidable coupling between the facilities a library uses and facilities that a user can customize, and the question becomes how much a library should expose that coupling to make users aware of the effects of customization. To pick an example, I sometimes see people complaining about whether or not some library uses standard allocators or not. In practice, one can customize allocation behavior by replacing the global operator new. But this is an intrusive customization which gives no guarantees to the user. For all the user knows, some implementations of a given library do not call operator new at all, but rather use an internal allocator with placement new. Should those facts be exposed to the user or not? The initial uses of a library would suggest not. You are arguing that as little detail as possible should be specified for a library. There is certainly merit in keeping things as simple as possible and not over-constraining implementors. But I'm saying that people can, will, and are customizing anyway, sometimes in ways not initially expected by the authors of a given library. So I don't see the issue of how much detail to expose as an open-and-shut case. It seems to me that the progression is towards customization; and that means exposing more implementation policies and details, so that when a user does customize something not originally anticipated by a library author, at least the user knows what to expect. And if a library is documented to be implemented in a certain way, then the user even gets some guarantees they otherwise would not get if the implementation were completely undocumented. Dave

"David B. Held" <dheld@codelogicconsulting.com> writes:
David Abrahams wrote:
And yet, the question is how much of a library's implementation should be exposed/documented so that the user knows what they are affecting when they make globally intrusive changes? I'm not suggesting that a library should be responsible for things outside of its control. I'm saying that we have an issue of unavoidable coupling between the facilities a library uses and facilities that a user can customize, and the question becomes how much a library should expose that coupling to make users aware of the effects of customization. To pick an example, I sometimes see people complaining about whether or not some library uses standard allocators or not. In practice, one can customize allocation behavior by replacing the global operator new. But this is an intrusive customization which gives no guarantees to the user. For all the user knows, some implementations of a given library do not call operator new at all, but rather use an internal allocator with placement new. Should those facts be exposed to the user or not? The initial uses of a library would suggest not. You are arguing that as little detail as possible should be specified for a library.
Not exactly.
There is certainly merit in keeping things as simple as possible and not over-constraining implementors.
It's not about freedom for implementors. It's about understandability for users.
But I'm saying that people can, will, and are customizing anyway, sometimes in ways not initially expected by the authors of a given library. So I don't see the issue of how much detail to expose as an open-and-shut case. It seems to me that the progression is towards customization; and that means exposing more implementation policies and details, so that when a user does customize something not originally anticipated by a library author, at least the user knows what to expect. And if a library is documented to be implemented in a certain way, then the user even gets some guarantees they otherwise would not get if the implementation were completely undocumented.
I understand what you're saying, but I think it's really a different issue from the one we're discussing. At issue is this question: Is it OK to say that an operation that uses some user-customizable functionality preserves all invariants in the face of an exception? You are saying, IIUC, "yes, if either a.) the only possibility of an exception arises before a user-customizable function is ever invoked, or b.) we also say that the user-customizable function is pure" I am saying that case a. is very rare, in part because it also requires that the customization is prohibited from throwing. If case a. arises I'd prefer to say something like "if an exception is thrown the customization is never invoked". I'm also saying that in case b. the requirement on the purity of the function is "intuitively obvious": clearly if my customization twiddles some bits that the operation has no knowledge of, the operation can't untwiddle them. So I prefer not to belabor that point. Really, the question at issue is "what conventions will we adopt for documenting exception safety?" I prefer conventions that will describe the 99% cases in a few understandable words, and that require more language for the other 1%. We have the freedom to invent our own jargon/terminology/colloquialisms to accomplish that. If it means that we need a few paragraphs of documentation for people to understand how to read the specifications, I think that's preferable. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
participants (4)
-
David Abrahams
-
David B. Held
-
Pavol Droba
-
Thorsten Ottosen