February 20, 2012
On 2/20/12 10:15 AM, dennis luehring wrote:
>> Again, I think this thread clarified we need the "Variant[string] info;"
>> member however we define the hierarchy.
>
> to use an mighty hyper map capable of holding all informative "values"
> will just follow in the same amount of non-using code, and the using
> code will be filled up with info["blub"], info["blab"], evil castings,
> sensless const key-string an still no proper way to show/use the
> information in an generic and typesafe way
>
> sorry but feels like throwing anway the signature conecpt and replace it
> with an runtime thing ... maybe we should also get rid of function
> signatures with "Variant[string] parameter" :}

I understand this seems loose, but again, when you want to do custom formatting or i18n this is the way to go. The job of rendering the exception as a string must be outsourced (heh) outside the exception, and Variant[string] is a simple mechanism to do so.

Andrei


February 20, 2012
On 2/20/12 10:16 AM, Nick Sabalausky wrote:
> "Andrei Alexandrescu"<SeeWebsiteForEmail@erdani.org>  wrote in message
> news:jhtq31$u8q$1@digitalmars.com...
>>
>> Again, I think this thread clarified we need the "Variant[string] info;"
>> member however we define the hierarchy.
>>
>
> I disagree. I don't see a need for that.

How would we address custom formatting of e.g. error messages?

Andrei

February 20, 2012
On Monday, 20 February 2012 at 15:50:08 UTC, Andrei Alexandrescu wrote:
> On 2/20/12 3:01 AM, foobar wrote:
>> On Monday, 20 February 2012 at 07:10:39 UTC, Andrei Alexandrescu
>> wrote:
>>> On 2/20/12 12:44 AM, foobar wrote:
>>>> I just died a little reading this. Are you suggesting that in
>>>> order to handle IO exceptions I need to: try { ...whatever... }
>>>> catch (PackageException!"std.io") {...} } catch
>>>> (PackageException!"tango.io") {...} } catch
>>>> (PackageException!"otherLib.io") {...} ...
>>>>
>>>> What the hell is wrong with just using an IOException?
>>>
>>> There's nothing wrong, but there's a possible misunderstanding. If
>>> tango.io and otherLib.io cooperate with std, then they'd originate
>>> exceptions in std.io (as opposed to their own). Do note that the
>>> issue is exactly the same if libraries use IOException - they all
>>> must agree on using the same nomenclature, whether it's called
>>> PackageException!"std.io" or IOException.
>>>
>>
>> The above is patently wrong. Are you suggesting that tango.io and
>> otherLib.io need to depend on Phobos IO?? If so, that removes the
>> benefits of using 3rd party libraries. If that's not your intention
>> (and I really hope it isn't!) than IOException must be defined in a
>> *separate* module that tango can depend on.
>
> Actually that just shuffles the matter around. Any setup does demand
> that some library (in this case most probably the standard library) will
> be a dependency knot because it defines the hierarchy that others should
> use.

Not accurate. A 3rd party library that want to be compatible will no doubt depend on the standard library's _exception hierarchy_ but that does *not* mean it should depend on the parallel functionality in the standard library. Per our example with IO, if I use tango.io I certainly do not want my application code to include redundantly both std.io and tango.io. I wanted to use tango.io as an *alternative* to std.io.

>
>> [Meta] side-note: It's extremely irritating when you demand utmost
>> pedantic reasoning from others while you often answer without
>> providing such pedantic reasoning yourself or worse answer with a
>> single word posts. That shows a complete lack of respect for others.
>> You seem to be of high regard for yourself which is not justified at
>> all given this attitude.
>
> When giving brief answers I was trying to maximize throughput in a couple of cases when the meaning was obvious from the context. Otherwise I do my best to elaborate my points. But I see how that can be irritating, I won't continue it.
>
>

Thank you.

> Andrei


February 20, 2012
On 2/20/12 10:31 AM, Sean Kelly wrote:
> On Feb 20, 2012, at 7:49 AM, Andrei Alexandrescu<SeeWebsiteForEmail@erdani.org>  wrote:
>>
>> Also, I think we can do better than defining the boilerplate constructor (see e.g. https://github.com/D-Programming-Language/phobos/pull/439). It's just a function. Consider:
>>
>> // this goes in the stdlib
>> void raise(ConcreteException)(string message, Throwable t = null, string f = __FILE__, size_t l = __LINE__)
>> {
>>   auto r = new ConcreteException;
>>   r.message = message;
>>   r.file = f;
>>   r.line = l;
>>   r.next = t;
>>   throw r;
>> }
>>
>> class AcmeException : Exception {}
>>
>> Now whenever you want to raise AcmeException, you say raise!AcmeException("message"). Also, raise may accept additional data that fills the Variant[string]. That makes exception definitions one-liners.
>
> What is gained here over the current approach:
>
> throw new AcmeException("message");
>
> Just eliminate the need for the ctor definition in the exception class?

Also possibly the definition of other constructors that set state. It's simple factorization.

Andrei
February 20, 2012
On 2/20/12 10:37 AM, foobar wrote:
> On Monday, 20 February 2012 at 15:50:08 UTC, Andrei Alexandrescu wrote:
>> Actually that just shuffles the matter around. Any setup does demand
>> that some library (in this case most probably the standard library) will
>> be a dependency knot because it defines the hierarchy that others should
>> use.
>
> Not accurate. A 3rd party library that want to be compatible will no
> doubt depend on the standard library's _exception hierarchy_ but that
> does *not* mean it should depend on the parallel functionality in the
> standard library. Per our example with IO, if I use tango.io I certainly
> do not want my application code to include redundantly both std.io and
> tango.io. I wanted to use tango.io as an *alternative* to std.io.

This is a confusion. Using PackageException!"std.io" does not require importing std.io. Conversely, using std.IOException _does_ require importing std.exceptions or whatnot. So from a dependency management viewpoint, PackageException is superior to IOException.

The converse disadvantage is that typos won't be caught during compilation. For example, using PackageException!"sdt.io" will go through no problem, but of course won't be caught by people waiting for a PackageException!"std.io".


Andrei

February 20, 2012
On Monday, 20 February 2012 at 16:37:28 UTC, Andrei Alexandrescu wrote:
> On 2/20/12 10:16 AM, Nick Sabalausky wrote:
>> "Andrei Alexandrescu"<SeeWebsiteForEmail@erdani.org>  wrote in message
>> news:jhtq31$u8q$1@digitalmars.com...
>>>
>>> Again, I think this thread clarified we need the "Variant[string] info;"
>>> member however we define the hierarchy.
>>>
>>
>> I disagree. I don't see a need for that.
>
> How would we address custom formatting of e.g. error messages?
>
> Andrei

Separation of concerns - exceptions are meant to notify the *developer* of errors. User facing error messages is a separate concern that exceptions should not be responsible for. it's not just outsourcing the translation strings, it's the developer's job to determine what if at all should be done with the exception.

Trivial example:  My mom enters a misspelled URL (e.g. goggle.com) in her browser, she does not know or care what 404 means. instead she gets a formated page suggesting her to check her spelling and probably a suggestion to try google.com instead.

the exception notifies the developer of the error, the developer does extra processing (e.g. to suggest similar valid websites) and the user get a friendly notification. clearly it doesn't make sense to put all this into the exception.
February 20, 2012
Am 20.02.2012 17:41, schrieb Andrei Alexandrescu:
> On 2/20/12 10:31 AM, Sean Kelly wrote:
>> On Feb 20, 2012, at 7:49 AM, Andrei
>> Alexandrescu<SeeWebsiteForEmail@erdani.org> wrote:
>>>
>>> Also, I think we can do better than defining the boilerplate
>>> constructor (see e.g.
>>> https://github.com/D-Programming-Language/phobos/pull/439). It's just
>>> a function. Consider:
>>>
>>> // this goes in the stdlib
>>> void raise(ConcreteException)(string message, Throwable t = null,
>>> string f = __FILE__, size_t l = __LINE__)
>>> {
>>> auto r = new ConcreteException;
>>> r.message = message;
>>> r.file = f;
>>> r.line = l;
>>> r.next = t;
>>> throw r;
>>> }
>>>
>>> class AcmeException : Exception {}
>>>
>>> Now whenever you want to raise AcmeException, you say
>>> raise!AcmeException("message"). Also, raise may accept additional
>>> data that fills the Variant[string]. That makes exception definitions
>>> one-liners.
>>
>> What is gained here over the current approach:
>>
>> throw new AcmeException("message");
>>
>> Just eliminate the need for the ctor definition in the exception class?
>
> Also possibly the definition of other constructors that set state. It's
> simple factorization.
>
> Andrei

If it's supposed to be simple factorization, then you should replace "throw r" with "return r". Then the name of that function doesn't make much sense anymore. But then you can better search for throw in user code and the stack traces aren't obfuscated anymore.

throw createEx!AcmeException("....");


Mafi
February 20, 2012
On 2/20/12 11:05 AM, foobar wrote:
> On Monday, 20 February 2012 at 16:37:28 UTC, Andrei Alexandrescu wrote:
>> On 2/20/12 10:16 AM, Nick Sabalausky wrote:
>>> "Andrei Alexandrescu"<SeeWebsiteForEmail@erdani.org> wrote in message
>>> news:jhtq31$u8q$1@digitalmars.com...
>>>>
>>>> Again, I think this thread clarified we need the "Variant[string]
>>>> info;"
>>>> member however we define the hierarchy.
>>>>
>>>
>>> I disagree. I don't see a need for that.
>>
>> How would we address custom formatting of e.g. error messages?
>>
>> Andrei
>
> Separation of concerns - exceptions are meant to notify the *developer*
> of errors. User facing error messages is a separate concern that
> exceptions should not be responsible for. it's not just outsourcing the
> translation strings, it's the developer's job to determine what if at
> all should be done with the exception.

At the end of the day, a human-readable error message must be properly formatted given some exception that signaled an error. So I disagree that exceptions are meant for the developer. They are mechanism, a means to an end.

> Trivial example: My mom enters a misspelled URL (e.g. goggle.com) in her
> browser, she does not know or care what 404 means. instead she gets a
> formated page suggesting her to check her spelling and probably a
> suggestion to try google.com instead.

Sure, and the question is how the message gets created.

> the exception notifies the developer of the error, the developer does
> extra processing (e.g. to suggest similar valid websites) and the user
> get a friendly notification. clearly it doesn't make sense to put all
> this into the exception.

That extra processing must format the message given the information passed by the exception. _Definitely_ it doesn't make sense to put the formatting processing in the exception. That's why shipping the information outside the exception in a generic format is necessary, hence the Variant[string].


Andrei
February 20, 2012
Le 18/02/2012 19:52, Andrei Alexandrescu a écrit :
> There's a discussion that started in a pull request:
>
> https://github.com/alexrp/phobos/commit/4b87dcf39efeb4ddafe8fe99a0ef9a529c0dcaca
>
>
> Let's come up with a good doctrine for exception defining and handling
> in Phobos. From experience I humbly submit that catching by type is most
> of the time useless.
>
>
> Andrei

By reading the discussion, and by travelling alone by car the whole day, I had plenty of time to think about all that. Here are some conclusion and a proposal.

1/ Andrei's proposal about transient is great. This is a useful property to know about Exceptions and so we should integrate it. This property must be pure and const, see why at point 4.

2/ Modules in phobos are organised according to what the do, not how they fail. So the Exception hierarchy using modules and package is not a good approach. We should use Exception in phobos that user or third party lib writter can use, to avoid Exception type proliferation.

3/ An Exception deserve its own type if it can additionnal carry data about the problem faced, or is supposed to be handled a very different way (ie, FileNotFoundException is likely to be handled differently that SecurityException on a function like remove). Most of the time, theses 2 caracteristics goes with each other.

4/ Sometime, Exception doesn't deserve its own type, but you may want to not match all of them. For example, if we have an OracleException with an errorcode as defined by oracle documentation, we may want to handle some of them differently.

For such a thing, proposal has been made in this thread. Let me expose mine. This is not revolutionary and is largely inspired by what was posted in this thread. The point is to specify it more clearly.

Let's start with the syntax :

try {
    // Stuff . . .
} catch(Exception e) if(e.transient == false) {
    // Handling . . .
}

If what is in the if is evaluated to false, then the catch block isn't selected and the Exception continue its propagation just like no catch block were present.

This syntax has proven to be convenient in template instanciation, and we should reuse it as much as possible (even if in our case, it is evaluated at runtime and not compiletime).

To ensure that it make sense, we need that what is in the if is pure and the Exception const. The execution of the test in the if must have no side effect.

If what is in the if block throw, then it happen the same than if something in the catch block throw : the new Exception is propagated, and the old one is linked to that new one.

Alternatively, we can decide that what is in the if must be nothrow too, but we still have to consider Errors, so it doesn't solve the problem and add useless constraints.

I used the transient property here, but basically any test that is pure should be usable. If the Exception is a more specific type, then we can use it's property and method, as long as it is pure.

Amaury
February 20, 2012
On 2/20/12 11:08 AM, Mafi wrote:
> If it's supposed to be simple factorization, then you should replace
> "throw r" with "return r". Then the name of that function doesn't make
> much sense anymore. But then you can better search for throw in user
> code and the stack traces aren't obfuscated anymore.
>
> throw createEx!AcmeException("....");

I think that's a great idea, thanks.

Andrei