Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2002-11-20 19:05:21


"William E. Kempf" <wekempf_at_[hidden]> writes:

> David Abrahams said:
>> "William E. Kempf" <wekempf_at_[hidden]> writes:
>>
>>>> There are workarounds for that problem. See
>>>> http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-closed.html#254
>>>
>>> Thanks for the link. Comments:
>>>
>>> * I personally don't agree with the rationale that not throwing
>>> bad_alloc when constructing from a string is not necessarily a bad
>>> thing. As bad as exception specifications are, they are at least
>>> useful as documentation
>>
>> Not very. Don't forget that derived classes pass.
>
> *being dumb* What do you mean by that last sentence?

If an exception specification says throw(X), any class derived from X
may be thrown, and that class can add arbitrary semantic value to
X. So an exception-specification doesn't tell you much about what can
actually be thrown.

>>> and this automatically adds another exception type to the list that
>>> may not have otherwise been there.
>>
>> Not unless your compiler is broken. Exception specifications are
>> strictly enforced at runtime.
>
> I was referring to specification as documentation, not as an actual
> specification in the code. For instance, the
> boost::thread_lock_error is specified to be thrown in the
> documentation of several Boost.Threads methods, but what's not
> documented (which means a bug either in the documentation or the
> implementation, but that answer is unsatisfying) is that this means
> std::bad_alloc may also be thrown.

Why? That just seems like a bad implementation of thread_lock_error.

> But, frankly, the using specification in the actual code would make
> this point even stronger, as this may mean a call to unexpected()
> instead.

I don't know what you're saying.

>>> At the very least, it would be nice if we had a boost::exception
>>> (derived from std::exception) as a base, which included the const
>>> char* constructor to eliminate the problem with the string
>>> constructor,
>>
>> There is no problem with the string constructor, because that
>> constructor doesn't exist in std::exception.
>
> No, but it does in the branches for logic_error and runtime_error.
> The logic is that if all of our exceptions are based of off
> boost::exception, we can avoid the issue found in those branches.
> (OK, this isn't an argument for having our own exceptions, exactly,
> but I wasn't trying to make that argument.)

What argument are you trying to make?

>>> and that ensured nothrow copies.
>>
>> You can't ensure that in a base class. A derived class can always
>> throw in its copy-ctor.
>
> Yeah, but that wasn't the point I was trying to make. I simply
> meant that IIF we do have a Boost exception heirarchy, it shouldn't
> force the issue of dynamic allocation of strings on the user at any
> node of the tree.

Good, we agree on that.

>>> No, but it is desirable to provide language neutral strings
>>
>> What's a language-neutral string? "42"?
>
> A string that's based on the users locale.
>
>>> that describe what exception was thrown, and possibly why and/or
>>> from where, etc. This isn't to say that what() is bad because
>>> it's not language neutral
>>
>> ?? It's as language-neutral as you make it. It's just a string.
>>
>>> only that there's (at least in some circumstances) a desire for a
>>> language neutral description of what went wrong.
>>
>> Localization should not the be the job of an exception class.
>
> This shows that you did understand what I was trying to convey,
> despite the numerous questions that do nothing but point out how
> badly I described the problem ;).

If I gave you just one coherent answer in all this mess, it doesn't
mean I understood what you were driving at all along. It only means we
managed to communicate without confusion at one point in the
conversation. I'm not trying to be anal about your description of "the
problem", whatever that may be. I really don't understand what you're
driving at.

And, BTW, I think that if there _is_ a problem, a good description
should precede any attempts to solve it.

> I don't expect the exception to provide localization, only that it
> provide the necessary hooks for localization to be easily
> implemented.

What do you think those should look like?

>> ?? Aren't we talking about whether a boost::exception is needed?
>> Wouldn't that just be derived from std::exception? What's the
>> problem?
>
> If you leave it just at the root of the tree, nothing. I just
> expected we'd have the logic_error and runtime_error branches as
> well... but that may have been a bad expectation.

I sure hope so. I would never use those exceptions if I cared about
behavior in low-memory situations.

>>>>> and possibly could be used to index into a catalog of language
>>>>> neutral strings for output.
>>>>
>>>> Existing what() does that.
>>>
>>> How so? I can think of a few hacks, but none seem completely
>>> satisfying.
>>
>> std::map<char const*, std::string, compare_cstring>?
>
> This assumes that the what() strings are all unique,

Show me another solution which doesn't rely on a similar assumption,
please.

> gives suboptimal performance in lookups,

Who cares? You just paid for stack unwinding!

> and doesn't allow for specifying data to be formatted into the
> string.

What do you mean? The translation backend has nothing to do with how
data gets into the string. The derived exception type can contain a
fixed-size buffer, for example.

> But at this point I think I can safely assume you don't care about
> these points, which is a valid point of view.

I'm not sure I understand enough to tell you whether I care.

>>> The only problem is how you allow the strings to be made language
>>> neutral. From what you said above, I assume you think there's a
>>> solution to that, but I don't see it. Care to point out what I'm
>>> not seeing?
>>
>> If there's an answer, it's in a different domain. I don't think that
>> belongs in an exception class.
>
> Yes, and no. The actual act of retrieving a localized string
> obviously doesn't belong in this domain. However, providing a key
> for looking up said strings, and a hook for formatting said strings
> with instance specific data, would sure be nice IMHO.

>
> // hypothetical code...
> try
> {
> ....
> }
> catch (const boost::exception& e)
> {
> std::string str = lookup(e.key());

  catch(std::exception& e)
  {
     std::string str = lookup(e.what());

> // 'str' no contains a locale specific string with replacable value
> // markers, for instance:
> // "bad_argument '${argument}' thrown in ${function}"
> std::cout << e.format(str) << std::endl;

Why go back to the exception object to do the formatting job here?

> // given the above hypothetical locale specific string we might get:
> // bad_argument 'first_arg' thrown in some_class::foo
> }
>
> Obviously a toy example, but I think this illustrates the idea.

I think you can encode all of that stuff into the what() strings:

  "bad_argument$3$my_function\0"

-- 
                       David Abrahams
   dave_at_[hidden] * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk