Boost logo

Boost :

From: William E. Kempf (wekempf_at_[hidden])
Date: 2002-11-21 09:56:46


David Abrahams said:
> "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.

But inheritance implies a certain relationship. In the specific case I
described, there's no relationship involved.

>>>> 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.

Then it's a bad implementation of std::out_of_range as well, since the
exact same case applies there.

>>>> 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?

Only that IIF we define our own, we should avoid the issues present in the
standard exception heirarchy.

>>>> 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.

Well, as poor a job as I've been doing, that's the only point I've been
trying to argue ;).

>>>> 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'd agree with that, but I do think you understand what I feel the problem
is. You've just not yet been convinced that that's what I've meant, and
only what I've meant.

>> 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?

Well, that's where I don't have a satisfactory answer. I know what I
consider to be the problem, but not what the solution could be. And maybe
there isn't a satisfactory solution.

>>> ?? 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.

Because of the implementation. The heirarchy isn't flawed, only the
implementation is. (And that's a bit drastic, as the link you gave points
out, since the solutions should be fairly trivial to implement.) I'd
expect us to have a similar heirarchy, but with the proposed
implementation that avoids the issues of memory allocations.

>>>>>> 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.

The problem is that the what() strings aren't enforcably unique. In fact,
in most cases they are user supplied, instead of implementation supplied.

>> gives suboptimal performance in lookups,
>
> Who cares? You just paid for stack unwinding!

Well, more importantly, it's suboptimal in memory usage. But that may not
be an issue for some people either.

>>>> 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"

That might be another approach, but would require strict specification of
what's returned from what(), and a more complex lookup/format mechanism.
The main problem I see with this approach is that any existing code that
expects what() to return a human readable (albiet unlocalized) string will
now be getting a string that's not easy to decipher.

William E. Kempf


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