February 21, 2012
On Tue, 21 Feb 2012 23:29:32 +0100, H. S. Teoh <hsteoh@quickfur.ath.cx> wrote:

> On Tue, Feb 21, 2012 at 03:15:19PM -0600, Andrei Alexandrescu wrote:
> [...]
>> A more debatable aspect of exceptions is the first-match rule in
>> catch blocks. All of OOP goes with best match, except here. But then
>> all code is together so the effect is small.
>
> Does it make sense to make it best-match? Or is that too risky since
> everyone expects it to be first-match?
>
>
Catch statements that are not in best-match order are a compile time error, g++ does that as a warning too.
February 22, 2012
On Tue, 21 Feb 2012 09:12:57 -0600, Adam D. Ruppe <destructionator@gmail.com> wrote:

> On Tuesday, 21 February 2012 at 02:33:15 UTC, Robert Jacques
> wrote:
>> Nope. See
>> (https://jshare.johnshopkins.edu/rjacque2/public_html/ )
>
>
> Any luck in getting the required patches into phobos?
>
> I'd love to see this full thing in there for the next release.
>
> It rox.

I'm in the process of cleaning up the required patches and submitting them. The first one's already in (https://github.com/sandford/phobos/commit/8b845d2a50bc20993afed7306f3d84921e4ac54b). I've almost got appender ready.
February 22, 2012
On Tuesday, February 21, 2012 14:15:03 Andrei Alexandrescu wrote:
> I thought I was pushing the generics angle, and OO people explained it to me that that was wrong.

You were just talking about applying OO policy to exceptions, which just doesn't make sense for most things, because they're just not polymorphic in terms of how they're handled.

> I'm sorry, I was unable to derive information from this post. It's a string of assertion without any backing.

Just look at exceptions. You catch them by type and then use that specific type. You don't generally operate on them via polymorphic functions. Derived classes usually hold more data but do not change the behavior of any existing functions. Rather, you look at the type of the exception and the values of the member variables in that concrete type to decide how to handle the exception based on that information. That's not particularly OO or polymorphic at all.

Yes, you can catch more generic exceptions instead of the concrete ones, but that doesn't generally mean that you end up calling virtual functions on the base class. Rather, it means that your code cares less about what exactly went wrong. You're still not likely to be calling a virtual function on the exception type, because exceptions carry information, not behavior.

The one major exception to this is toString. Having generic error message generating capabilities is useful. And not even that needs to be polymorphic. With Exception, the return value of toString is generated from the msg property which was passed in via its constructor. And toString isn't something that you normally override with Exception. Rather, it's the msg argument which changes. At minimum, if you do override toString, you need to call the base class' toString or you'll lose the stack trace. It's just not really designed with overriding in mind.

I really don't see how anyone can make much of an argument for exceptions being OO beyond the fact that they're objects given that handling them means doing the complete opposite of typical OO. With exceptions, it's how they're handled that changes from type to type, not their internal behavior, whereas OO focuses on changing the behavior of functions in derived classes. And with exceptions, you use the concrete types and not an abstract interface, whereas in OO, the idea is to use an abstract interface.

So, I don't see much point in trying to force OO principles on exceptions. Trying to treat them more generically with regard to generating error messages makes some sense, but that's about it. And that still isn't particularly OO - especially when the proposed solution is to use Variant[string] rather than to do something with toString. But if you want to change the message formatting at the catch point (just like all of the other exception behavior is generally done at the catch point), you can't do it with toString (at least, not without changing the internal state of the exception before calling toString). OO just doesn't fit.

- Jonathan M Davis
February 22, 2012
On 2/21/12 6:11 PM, Robert Jacques wrote:
> On Tue, 21 Feb 2012 09:12:57 -0600, Adam D. Ruppe
> <destructionator@gmail.com> wrote:
>
>> On Tuesday, 21 February 2012 at 02:33:15 UTC, Robert Jacques
>> wrote:
>>> Nope. See
>>> (https://jshare.johnshopkins.edu/rjacque2/public_html/ )
>>
>>
>> Any luck in getting the required patches into phobos?
>>
>> I'd love to see this full thing in there for the next release.
>>
>> It rox.
>
> I'm in the process of cleaning up the required patches and submitting
> them. The first one's already in
> (https://github.com/sandford/phobos/commit/8b845d2a50bc20993afed7306f3d84921e4ac54b).
> I've almost got appender ready.

Are the changes substantial enough to put them through the review process?

Andrei
February 22, 2012
On Tue, Feb 21, 2012 at 07:43:32PM -0500, Jonathan M Davis wrote:
> On Tuesday, February 21, 2012 14:15:03 Andrei Alexandrescu wrote:
> > I thought I was pushing the generics angle, and OO people explained it to me that that was wrong.

I've changed my mind. Now I'm trying to see if the generics angle has some possibilities. Maybe, maybe not, but we'll never know without experimenting with it. I think your is_transient idea can be expanded upon.

The way exceptions are currently implemented, they only carry information, not behaviour, as Jonathan said rightly.  The try/catch mechanism essentially reduces to "I've hit a problem I don't know how to solve, here's a description of it". There's no behaviour in there. The throwing code has already given up.  It's up to the catcher to interpret the description of the problem and figure out how to recover. To recover well, the catcher must know the intimate details of the problem well. So you have the situation of a specific catcher catching a specific Exception subclass. This is not an ideal situation, because now high-level code needs to know the specifics of low-level errors.

With your is_transient idea, though, this begins to change. Now we're no longer just describing the problem.  When is_transient=1, it means the thrower is suggesting that perhaps retrying would help. Of course, it's up to the catcher whether or not to follow through with this suggestion, but it's one step up from "here's a description of the problem, figure out the solution yourself". But now the catcher doesn't necessarily have to know the specifics of the low-level problem. It knows at least one strategy that might fix the problem, regardless of what the problem is: retry the operation. This is good, because the low-level code, which knows the problem best, can offer a useful suggestion (retry). The high-level code can just take the suggestion or not; it no longer needs to know low-level details.

But why stop there? Since the low-level code knows all the dirty details about the problem, it's in the best position to offer meaningful recovery suggestions. It just has to communicate these possible recovery strategies to the high-level code, and let the high-level code decide what to do. The high-level code doesn't need to know how to implement these strategies -- it's not in the best position to know that anyway. It just knows, here's a list of recovery strategies, I can go ahead with one of them, or just call it quits and unwind the stack. The low-level code is what implements each strategy.

Of course, in order for the high-level code to meaningfully choose between alternative strategies, the strategies themselves must be generic concepts; otherwise we're still tying high-level code to low-level details. So we need to identify generic categories of exceptions for which this kind of generic recovery is meaningful -- which is what I've done in another post.

I won't repeat the details here, but I just want to say that I think this angle merits some investigation. It allows us to factor out exceptions which can be resolved by commonly used recovery strategies so that we don't have to keep writing tons and tons of exception-specific recovery code everywhere. Some specific code is still needed, no doubt, there's always special cases that need specific handling.  But if enough exceptions can be adequately dealt with generically, then we don't need to write specific code for them. We can simply reuse generic recovery solutions.


T

-- 
Real Programmers use "cat > a.out".
February 22, 2012
On 2012-02-21 22:08, Andrei Alexandrescu wrote:
> On 2/21/12 2:42 PM, Jacob Carlborg wrote:
>> On 2012-02-21 21:27, Andrei Alexandrescu wrote:
>>> On 2/21/12 2:26 PM, Jacob Carlborg wrote:
>>>> As I said, it seems you want to push up implementation details specific
>>>> to a given subclass to the base class even though it shouldn't be
>>>> pushed
>>>> up.
>>>
>>> I explained that doing so allows for proper formatting of error
>>> messages. So it should pushed up.
>>>
>>> Andrei
>>
>> Well, I don't think that is the right approach. As many others have
>> explained, error messages are only a small part of exception handling.
>
> I agree. Also, one interface function is only a small part of a class
> hierarchy.
>
>> If you do want to have a generic way of getting an error message out of
>> an exception, what's wrong with toString? Or a new method that formats
>> the error messages. No need to push up the instance variables to the
>> base class.
>
> This has been answered in the long thread. In brief, toString loses too
> much information and putting formatting inside exceptions is not the
> right place.
>
>
> Andrei

Now I'm completely lost. According to what I've read this is thread this is exactly what you want to do, put the formatting inside the exceptions.

-- 
/Jacob Carlborg
February 22, 2012
On Tue, Feb 21, 2012 at 08:56:03PM +0100, deadalnix wrote:
> Le 21/02/2012 20:00, H. S. Teoh a écrit :
[...]
> >You're right, that would be unnecessary duplication, especially since an unhandled Condition becomes a thrown Exception anyway, and it's a very bad idea to duplicate the entire Exception hierarchy in Condition.
> >
> >Only thing is, then the handler will have to downcast the Exception to get to the useful info. This may lead to messy code. But it's something we should investigate.
> >
> 
> Yes, I'm aware of the problem and it is real. I have no good solution for it now.

I have an idea. What if handlers took *two* arguments, a Condition, and a (possibly derived) Exception object? The raise system would then match conditions to handlers by both the Condition type and derived Exception type. The handler then has access to the particular derived object that it wants to handle without needing to downcast. So it sorta simulates a catch(DerivedException).

It's a bit harder to implement, though... we'll need to store TypeInfo for each handler and match it up with the Condition being raised. But I'm assuming this isn't too much more than what the runtime is already doing with Exceptions anyway, so performance-wise it should be acceptable.

And while we're at it, I think we should just stop pretending this is still the same system as Lisp, and just rename Condition to RecoveryStrategy or RecoveryOpts or something along those lines, since that's what it is.


[...]
> >To maximize usability and minimize redundancy and bloat, I'm thinking we should define categories based on what recovery actions are *actually available*, rather than what actions are *potentially* available. So to that end, it's not really categorization per se, but more of a way of describing what recovery strategies are actually available.
> >
> 
> Yes indeed. Exception should provide data about what the problem IS, condition on what are option to recover.

Yeah, I think it makes sense to rename Condition to RecoveryStrategy or RecoveryOpts. The recovery choices aren't a "condition"; the Exception object is the condition, the choices are recovery strategies.


[...]
> >Each operation should have a single condition with a well-defined set of recovery methods, not some arbitrary combination of multiple conditions.
> >
> >What do you think?
> >
> 
> It is exactly what lead me to create template for such cases. Additionnaly, thoses templates should include a way to generate the Exception, but I ran into a strangeness of D when exprimenting with and did had time to come up with something working for that. The condition handling and the actual operation must be separated to avoid code duplication and ensure separation of concerns.

Yep.


> The current design allow to create new Conditions, in the lib but also in user code.
> 
> If we can find a way to handle properly the Exception crazy casting problem we have here a very nice way to handle errors.

Would it be possible to add that second argument to handlers? I think that will solve the problem. But it will take a bit more effort to implement.


T

-- 
"How are you doing?" "Doing what?"
February 22, 2012
On Wednesday, February 22, 2012 08:22:21 Jacob Carlborg wrote:
> Now I'm completely lost. According to what I've read this is thread this is exactly what you want to do, put the formatting inside the exceptions.

No. He wants to provide a way for an external function to generically generate strings according to the format that you want when you generate the string. So, some function would take a formatting string of some kind and then read the corresponding values form the Variant[string] in Exception and generate a string according to that format string. How exactly that works, I don't understand (something about a string template language), but that's the idea.

So, while you could still use toString, there would be a way to generate strings formatted the way that _you_ want rather than how toString would do it - and to do it in a generic manner.

As long as this doesn't mean using Variant[string] as the way to inject all of the extra data into exceptions and we still use an exception hierarchy with the appropriate data members in derived exceptions, then I don't really see that as a problem. The problem is if we then also get rid of the hierarchy and/or try and put all of the data is the Variant[string] and only in the Variant[string].

>From the sounds of it, we have _some_ agreement to have an exception hierarchy
with data members in derived classes where appropriate but to add the Variant[string] bit to Exception to enable the passing of other data that you might want but is not in the exception type normally as well as enable the fancy string formatting stuff that Andrei wants. But this thread is so long and complicated that I think that many of us are just confused.

- Jonathan M Davis
February 22, 2012
On 2012-02-22 08:33, Jonathan M Davis wrote:
> On Wednesday, February 22, 2012 08:22:21 Jacob Carlborg wrote:
>> Now I'm completely lost. According to what I've read this is thread this
>> is exactly what you want to do, put the formatting inside the exceptions.
>
> No. He wants to provide a way for an external function to generically generate
> strings according to the format that you want when you generate the string.
> So, some function would take a formatting string of some kind and then read
> the corresponding values form the Variant[string] in Exception and generate a
> string according to that format string. How exactly that works, I don't
> understand (something about a string template language), but that's the idea.
>
> So, while you could still use toString, there would be a way to generate
> strings formatted the way that _you_ want rather than how toString would do it
> - and to do it in a generic manner.
>
> As long as this doesn't mean using Variant[string] as the way to inject all of
> the extra data into exceptions and we still use an exception hierarchy with
> the appropriate data members in derived exceptions, then I don't really see
> that as a problem. The problem is if we then also get rid of the hierarchy
> and/or try and put all of the data is the Variant[string] and only in the
> Variant[string].

I agree.

>> From the sounds of it, we have _some_ agreement to have an exception hierarchy
> with data members in derived classes where appropriate but to add the
> Variant[string] bit to Exception to enable the passing of other data that you
> might want but is not in the exception type normally as well as enable the
> fancy string formatting stuff that Andrei wants. But this thread is so long and
> complicated that I think that many of us are just confused.
>
> - Jonathan M Davis

Ok, I see.

-- 
/Jacob Carlborg
February 22, 2012
Le 22/02/2012 08:32, H. S. Teoh a écrit :
> On Tue, Feb 21, 2012 at 08:56:03PM +0100, deadalnix wrote:
>> Le 21/02/2012 20:00, H. S. Teoh a écrit :
> [...]
>>> You're right, that would be unnecessary duplication, especially since
>>> an unhandled Condition becomes a thrown Exception anyway, and it's a
>>> very bad idea to duplicate the entire Exception hierarchy in
>>> Condition.
>>>
>>> Only thing is, then the handler will have to downcast the Exception
>>> to get to the useful info. This may lead to messy code. But it's
>>> something we should investigate.
>>>
>>
>> Yes, I'm aware of the problem and it is real. I have no good solution
>> for it now.
>
> I have an idea. What if handlers took *two* arguments, a Condition, and
> a (possibly derived) Exception object? The raise system would then match
> conditions to handlers by both the Condition type and derived Exception
> type. The handler then has access to the particular derived object that
> it wants to handle without needing to downcast. So it sorta simulates a
> catch(DerivedException).
>
Well I have no idea how to implement that. Let's put some thinking into this, it certainly an option. However, this require to create the Exception, even if in many cases, it will not be usefull.

About the name, it matters, but isn't the big issue here. When we have something working well, we could think about names. As the concept may be changed again, naming isn't that important.