February 21, 2012
On Tuesday, February 21, 2012 00:15:48 H. S. Teoh wrote:
> TRANSITIVITY

I still contend that this useless, because you need to know what went wrong to know whether you actually want to retry anything. And just because the particular operation that threw could be retried again doesn't mean that the code that catches the exception can retry the function that _it_ called which resulted in an exception somewhere down the call stack. And often, you don't even know which function it was that was called within the try block. So, I don't see how transivity really matters. If you know what what wrong - which the type of the exception will tell you - then _that_ is what helps your code make a useful decision as to what to do, not a transivity property.

So, yes. A particular exception type is generally transitive or not, but you know that by the nature of the type and the problem that it represents. I don't see how focusing on transivity is useful.

> The try-catch mechanism is not adequate to implement all the recovery actions described above. As I've said before when discussing what I called the Lispian model, some of these recovery actions need to happen *in the context where the exception was thrown*. Once the stack unwinds, it may not be possible to recover anymore, because the execution context of the original code is gone.

> This is where the Lispian model really shines. To summarize:

try-catch and Exceptions are built into the language. Exceptions are part of not only the standard library but the runtime. They're not perfect, but they _work_. I really think that this whole thing is being way overthought and blown out of proportion.

Using another recovery mechanism in your programs (built on top of exceptions or otherwise) is fine, but I really don't see a need to seriously alter how error handling is done in the language as a whole. We're _way_ past the point where it makes sense to completely redesign how exceptions work. And I _really_ don't think that it's a good idea to change anything major about how error handling is done in the standard library without a lot of real world experience with whatever you want to replace it with. And we don't have that.

So, I see no problem with you experimenting, but I don't think that we should be drastically changing how the standard library functions with regards to exceptions. We would definitely gain something by cleaning up how they're organized, and maybe adding additional capabilites to improve their printing abilities like Andrei wants to do would be of some value, but we don't need a complete redesign, just some tweaks.

- Jonathan M Davis
February 21, 2012
On Tuesday, February 21, 2012 08:15:29 Andrei Alexandrescu wrote:
> On 2/21/12 4:40 AM, Vincent wrote:
> > On Saturday, 18 February 2012 at 18:52:05 UTC, Andrei Alexandrescu wrote:
> >> From experience I humbly submit that catching by type is most of the time useless.
> > 
> > Completely disagree. Types allow to control place for "catch". Say, some deeply nested function catches its own exceptions, while outer function catches the rest - exceptions higher in hierarchy. But to have benefit you have to create exceptions hierarchy - this is the main point.
> 
> As the next hundreds of messages discuss, matters are not all that simple :o).

It probably should be though. I think that there's a lot of overthinking going on here.

We need to have our exceptions organized into a hierarchy so that you can catch them based on what went wrong. That is the main thing that we're missing IMHO.

Adding extra capabilities along side that is fine as long as they make sense. Adding a Variant[string] property for the purpose of putting non-standard information in your exceptions which don't merit a new exception type makes some sense. But if it makes sense to catch an exception based on that information, then it probably merits a new type. Adding improved string formatting cabilities also makes some sense.

But I don't think that we need to drastically overhaul how exceptions work, and a lot of this discussion is straying into left field.

- Jonathan M Davis
February 21, 2012
Le 21/02/2012 20:00, H. S. Teoh a écrit :
> On Tue, Feb 21, 2012 at 06:24:01PM +0100, deadalnix wrote:
>> Le 21/02/2012 18:10, H. S. Teoh a écrit :
> [...]
>>> True, and there's nothing to stop you from digging into the details
>>> of the raised Condition if you want to. I did consider implementing
>>> Conditions as some kind of class hierarchy, so that the generic
>>> categories are at the top, underneath Condition, then actual specific
>>> Conditions can extend them. If your handler knows of a specific
>>> Condition, then you can access any pertinent additional info, and
>>> make decisions based on that.
>>>
>>> But what I wanted to know was, can you still do something meaningful
>>> even if you knew nothing beyond the top-level generic categories of
>>> Conditions? That way, your handler will still work with new
>>> Conditions that you've never seen before.
> [...]
>> And here come an idea of mine :
>>
>> If the Condition has a way to provide the Exception associated. So you
>> can get the hierarchy from the Exception, and you don't need to creat
>> two hierachy of classes just for the bloat.
>
> 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.

>
>> You'll fond attached some sketching code. What do you think of it ?
>
> Is this the same code you attached in an earlier post? I did look over
> it, sorry, didn't have time to respond earlier. I like the idea of
> wrapping retryable code in the runTransient template, that way we
> minimize the amount of boilerplate needed to actually use this feature.
>
> Oh wait, you've added some new stuff. Let's see...
>
> Hmm, I like the idea of providing default handlers for some
> commonly-encountered situations. Reduces the amount of boilerplate.  And
> there's always the option of manually defining a handler if you need to.
> +1.
>
>
> I was considering more last night how to implement this system. I think
> I change my mind about having a common Condition base class. The whole
> idea is that every major category would be defined by what kinds of
> actions are available, so they are quite distinct from each other. I
> don't want to reinvent another hierarchy to represent problems; we
> already have an Exception hierarchy for that. So the different
> Conditions need to be qualitatively different.
>
> 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.

> In other words, an input error where you can recover by skipping the bad
> data is qualitatively different from an input error where skipping
> doesn't fix the problem. These two should be treated as distinct
> Conditions. Basically, I want to guarantee that for some Condition c,
> action A will *always* be available to the handler. Then the handler
> won't need excessive checking (if A1 is available but A2 is not, then
> use A1; else if A1 is not available but A2 is available, ... etc.). It
> can count on all options being actually present.
>

Agreed.

> Back to your code. We can implement this idea by defining a template for
> each of the possible conditions. So code in runTransient always raises a
> transient condition if it fails, runReroutable always raises a
> reroutable condition if it fails (reroutable = failing component X can
> be replaced by component Y). I don't know if this is too inflexible, but
> trying to mix multiple conditions into a single operation seems to turn
> the code into spaghetti:
>
> 	int x, y, z;
> 	retry1:
> 		doSomething(x, y, z);
> 	retry2:
> 		if (problem1)
> 			raise(condition1);
> 		else if (problem2)
> 			raise(condition2);
> 		...
> 	handleCondition(condition1):
> 		if (recoveryAction1) {
> 			fiddleWith(x);
> 			goto retry1;
> 		} else if (recoveryAction2) {
> 			doSomethingElse(x,y,z);
> 			goto retry2;
> 		}
> 	handleCondition(condition2):
> 		if (recoveryAction3) {
> 			fiddleWith(y);
> 			goto retry1;
> 		} else if (recoveryAction4) {
> 			fiddleWith(z);
> 			doSomethingElse(x,y,z);
> 			goto retry2;
> 		}
>
> So I don't think this is the right way to go. 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.

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.
February 21, 2012
On 2012-02-21 09:15, H. S. Teoh wrote:
> All of this heated debate has led me to reconsider our whole concept of
> exceptions. It seems that we're squabbling over little details in
> existing paradigms. But what of the big picture? What *is* an exception
> anyway? We all know the textbook definition, but clearly something is
> missing since we can't seem to agree how it should be implemented.
>
>  ...

I think I like the idea in general.

-- 
/Jacob Carlborg
February 21, 2012
On 2012-02-21 19:33, Juan Manuel Cabo wrote:
>> That because you can't (shouldn't) push up implementations specific to a given subclass. Why don't we only have one
>> class, Object, and add a Variant[string] there.
>>
>> Do you see how stupid that is.
>
> As stupid as any database API which returns result items as Variant[string] or
> string[string], but it works. (the sad part is that one has to rely a bit on
> convention, but convention can be standardized (string constants) and measures
> taken when deviated so that it is done gracefuly).

That's because we are limited by the database API. If you created a new database from scratch, completely written in D, perhaps even object oriented, you could return the correct object form the beginning.

> Do you have an alternative solution that allows to extend an exception
> object with extra information, while keeping it the same class?

No, but that's what subclasses are used for.

> So if one removes the bad reasons to create new Exception types, then the
> ones that DO get created are solid, standard, reusable, and can withstand
> the test of time. Because they would be open for extension but closed for
> source code modification.

-- 
/Jacob Carlborg
February 21, 2012
On 2/21/12 12:03 PM, Jacob Carlborg wrote:
> On 2012-02-21 17:57, Andrei Alexandrescu wrote:
>> On 2/21/12 10:50 AM, Juan Manuel Cabo wrote:
>>> I thought that an alternative to Variant[string] would be to have some
>>> virtual
>>> functions overrideable (getExceptionData(string dataName) or something).
>>> but they would all have to return Object or Variant, so it's the same
>>> thing.
>>
>> Exactly. By and large, I think in the fire of the debate too many people
>> in this thread have forgotten to apply a simple OO design principle:
>> push policy up and implementation down. Any good primitive pushed up the
>> exception hierarchy is a huge win, and any design that advocates
>> reliance on concrete types is admitting defeat.
>>
>> Andrei
>
> That because you can't (shouldn't) push up implementations specific to a
> given subclass. Why don't we only have one class, Object, and add a
> Variant[string] there.
>
> Do you see how stupid that is.

I think I do. It's also fair to ask you if you are sure you understood my point.

Andrei


February 21, 2012
On 2/21/12 1:17 PM, Jonathan M Davis wrote:
> On Tuesday, February 21, 2012 10:57:20 Andrei Alexandrescu wrote:
>> On 2/21/12 10:50 AM, Juan Manuel Cabo wrote:
>>> I thought that an alternative to Variant[string] would be to have some
>>> virtual functions overrideable (getExceptionData(string dataName) or
>>> something). but they would all have to return Object or Variant, so it's
>>> the same thing.
>> Exactly. By and large, I think in the fire of the debate too many people
>> in this thread have forgotten to apply a simple OO design principle:
>> push policy up and implementation down. Any good primitive pushed up the
>> exception hierarchy is a huge win, and any design that advocates
>> reliance on concrete types is admitting defeat.
>
> Exceptions do _not_ lend themselves to polymorphism. Having them in a type
> hierarchy is useful. It allows you to deal with them at varying levels of
> abstractions. But ultimately, you deal with the concrete types, _not_ an
> abstract interface. In that sense, they're not OO _at all_.

Well this is just a series of assertions that conveys no information.

> Adding a Variant[string] property to allow adding on additional information if
> a particular application finds it useful may be a good thing to do. But it
> should be an _add on_, not the core design.

Again, just an assertion.

> Aside from printing strings,
> trying to deal with exceptions generically just does not make sense.

Assertion.

> At best,
> you might care about a common exception rather than a more specific one in
> particular case (e.g. catching IOException rather than FileException). But if
> you're trying to actually handle the exception in any real way rather than
> just print out a message, you need the concrete type, not an abstract
> interface.

Assertion.

> I think that you're pushing the OO angle too hard onto exceptions.

I thought I was pushing the generics angle, and OO people explained it to me that that was wrong.

> They're not
> completely separated from it, but they really aren't classic OO and shouldn't
> be treated as such. If anything, they're inverted, because you frequently try
> and deal with as concrete a type as possible rather than as abstract a type as
> possible. The hierarchy aspect is really the only truly OO aspect of
> exceptions IMHO. For the most part, polymorphism just doesn't enter into it.
> And Exception really already declares the few functions where it does.

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


Andrei
February 21, 2012
On 2012-02-21 21:06, Andrei Alexandrescu wrote:
> On 2/21/12 12:03 PM, Jacob Carlborg wrote:
>> On 2012-02-21 17:57, Andrei Alexandrescu wrote:
>>> On 2/21/12 10:50 AM, Juan Manuel Cabo wrote:
>>>> I thought that an alternative to Variant[string] would be to have some
>>>> virtual
>>>> functions overrideable (getExceptionData(string dataName) or
>>>> something).
>>>> but they would all have to return Object or Variant, so it's the same
>>>> thing.
>>>
>>> Exactly. By and large, I think in the fire of the debate too many people
>>> in this thread have forgotten to apply a simple OO design principle:
>>> push policy up and implementation down. Any good primitive pushed up the
>>> exception hierarchy is a huge win, and any design that advocates
>>> reliance on concrete types is admitting defeat.
>>>
>>> Andrei
>>
>> That because you can't (shouldn't) push up implementations specific to a
>> given subclass. Why don't we only have one class, Object, and add a
>> Variant[string] there.
>>
>> Do you see how stupid that is.
>
> I think I do. It's also fair to ask you if you are sure you understood
> my point.
>
> Andrei

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.

-- 
/Jacob Carlborg
February 21, 2012
Le 21/02/2012 00:23, Andrei Alexandrescu a écrit :
> On 2/20/12 4:44 PM, Juan Manuel Cabo wrote:
>> HAhaha, it sometimes feel as though people are afraid that the
>> Variant[string]
>> idea is to never use plain old variables and never use exception
>> subclasses. :-)
>>
>> On the contrary, the idea is so that plain old variables and exception
>> subclasses
>> can be created for the right reasons, and to remove cases where they need
>> to be created for the wrong reasons.
>
> Yah, I think there's a lot of confusion and consequent apprehension
> regarding this. Thanks for attempting to clarify things.
>
> Andrei
>

So it doesn't help. Dulb subclasses of Exceptions are done mostly to be able to catch them. To avoid useless subclasses, we need a more precise way to catch Exception than the type only.

This Variant[string] doesn't help.
February 21, 2012
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