February 20, 2012
Because the default behavior of the function regarding retries can be
undesirable.
What If you're willing to call the function for the first one which succeeds?
Implementing retry inside the function, which tries is a violation of
single-responsibility principle.

On Sun, Feb 19, 2012 at 10:54 AM, H. S. Teoh <hsteoh@quickfur.ath.cx> wrote:
> On Sun, Feb 19, 2012 at 12:43:58AM -0600, Andrei Alexandrescu wrote:
>> On 2/18/12 8:00 PM, H. S. Teoh wrote:
>> >> From this and other posts I'd say we need to design the base exception
>> >>classes better, for example by defining an overridable property isTransient that tells caller code whether retrying might help.
>> >
>> >Just because an exception is transient doesn't mean it makes sense to try again. For example, saveFileMenu() might read a filename from the user, then save the data to a file. If the user types an invalid filename, you will get an InvalidFilename exception. From an abstract point of view, an invalid filename is not a transient problem: retrying the invalid filename won't make the problem go away. But the application in this case *wants* to repeat the operation by asking the user for a *different* filename.
>> >
>> >On the other hand, if the same exception happens in an app that's trying to read a configuration file, then it *shouldn't* retry the operation.
>>
>> I'm thinking an error is transient if retrying the operation with the same exact data may succeed. That's a definition that's simple, useful, and easy to operate with.
> [...]
>
> But if that's the case, what's the use of an exception at all? Why doesn't the function concerned simply retry on its own? Network stack code does that. It would be nightmarish to program network applications if you always have to implement retry on your own (much less use *exceptions* to handle them)!
>
>
> T
>
> --
> Let's not fight disease by killing the patient. -- Sean 'Shaleh' Perry



-- 
Bye,
Gor Gyolchanyan.
February 20, 2012
On Monday, 20 February 2012 at 09:01:18 UTC, foobar wrote:
...
>>> AS Nick wrote, it seems you have a complete lack of understanding of
>>> how exceptions work which is unsurprising coming from a c++ expert.
...
> "even a broken clock shows the right time twice a day"
...
>I get that you are a templates master,
> that does *NOT* mean everything must be made generic.
> You seem to prove the old saying that when all you have is a hammer everything looks like a nail.
>
> [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.

Please calm down and don't be so rude. Andrei doesn't have a clue
how exceptions work? He just wants to apply his template schtick
to everything? Give me a break.

I find this discussion rather interesting (and I look forward to
hearing Andrei's thoughts on H. S. Teoh's condition handler
idea), but I think if all you want is to attack the idea of even
discussing this, your voice has already been heard.

John
February 20, 2012
On Mon, Feb 20, 2012 at 01:10:39AM -0600, 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 exception hierarchy and the phobos module hierarchy are two different things. They should not be unnecessarily coupled.

You *want* exceptions in the exception hierarchy to be maximally reusable by code OUTSIDE of the phobos module that first introduced them. You want things like ParseError and LexicalError instead of StdGetoptError and StdJsonLexicalError, because then user code can *reuse* these exception types! *That* is what reduces boilerplate, since otherwise user code would have to define their own exceptions, thereby incurring lots of boilerplate and code duplication.


> ModuleException and PackageException have one important thing going for them: they automate away a good amount of boilerplate, which makes them interesting for me to look at, and worth sharing as long as we're brainstorming. The associated issues as clear as the advantages. Probably ModuleException is too specific to be interesting, but PackageException seems useful.
[...]

They do not automate away boilerplate; they merely transplant said boilerplate into user code by making it impossible for user code to reuse these exceptions. Which actually amounts to *more* boilerplate, since every user app will be introducing their own exception types rather than reusing what's already in the standard library.


T

-- 
"Outlook not so good." That magic 8-ball knows everything! I'll ask about Exchange Server next. -- (Stolen from the net)
February 20, 2012
On 2/20/12 1:38 AM, Jonathan M Davis wrote:
> On Monday, February 20, 2012 01:10:39 Andrei Alexandrescu wrote:
>> ModuleException and PackageException have one important thing going for
>> them: they automate away a good amount of boilerplate, which makes them
>> interesting for me to look at, and worth sharing as long as we're
>> brainstorming. The associated issues as clear as the advantages.
>> Probably ModuleException is too specific to be interesting, but
>> PackageException seems useful.
>
> It saves no boilerplate at the catch point, because you have to know what
> you're catching to do anything useful with it. It could be that you choose to
> catch a common exception rather than a specific one (e.g. IOException instead
> of FileException), but regardless of whether you use templates or mixins or
> whatever to generate the exception type's source code, you still need to write
> the handling code by hand. Handling code is _not_ the sort of thing that can
> be automated.

Absolutely. For catching we're looking for allowing centralization, not for automation.

> And as for saving boilerplate in defining exceptions, well some of that could
> be done via mixins, but since useful exceptions often have additional member
> variables, you're going to have to write many of them by hand anyway.

Again, I think this thread clarified we need the "Variant[string] info;" member however we define the hierarchy.

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.

> And as has been said before, ultimately the module that an exception comes
> from doesn't mean much. It's what went wrong that matters. And ideally, the
> standard library would have exception types that user code would throw or
> derive its own exception types from, in which case the exception types get
> even more divorced from the modules that they're declared in. So, ultimately,
> tying exceptions to modules or packages is _not_ a good idea in the general
> case. Sometimes it makes sense - particularly if you're talking about making a
> base exception type which a project as a whole uses (e.g. a PostgresException
> for a postgres library) - but in general, it's a bad approach, and it's one
> that we should be moving away from.

I tend to agree, particularly because it's easier for people to remember express names instead of origins encoded by module. Ironically, many of Phobos' exceptions today follow the exception-to-module correspondence. Still I think it's worth keeping in mind the possibility of having the PackageException as a base trail for various exceptions specific to a package.


Andrei
February 20, 2012
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.

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


Andrei
February 20, 2012
On Sat, 18 Feb 2012 19:58:14 -0000, H. S. Teoh <hsteoh@quickfur.ath.cx> wrote:

> On Sat, Feb 18, 2012 at 08:18:53PM +0100, Nathan M. Swan wrote:
>> On Saturday, 18 February 2012 at 18:52:05 UTC, Andrei Alexandrescu
>> wrote:
>> >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.
> [...]
>> Here's a compromise I would suggest: we have the different exception
>> types for different exceptional behaviors, but still they all
>> descend from a common exception type that has a field with the
>> module name; this way, the client can choose which way they want to
>> go.
>
> I think deadalnix's approach is better. Exceptions should not be
> categorized by module. What if the module depends on submodules? Then
> catching only that module's exceptions will miss exceptions thrown from
> submodules. No, exceptions need to be based on *semantics* rather than
> modules, like CommandLineException, not GetOptException.

The way I currently prefer to use exceptions in C++ is to have 1 exception type per module.  That module will catch and wrap *all* exceptions thrown by modules it calls. i.e.

[somemodule.cpp]
...
try
{
...
}
catch(OtherModuleException &ex)
{
  throw SomeModuleException("lalala", ex);
}

In this way I know, when calling a method in SomeModule, the only exception I need to catch is SomeModuleException.

So, code which uses multiple modules might look like..

try
{
SomeModule a = new..
OtherModule b = new ..
...
a->method();
...
b->method();
}
catch(SomeModuleException ex)
{
...
}
catch(OtherModuleException ex)
{
...
}

where typically one of those modules is something like a tcpip socket module, or a database module and the other may be something much more specific/different (which internally could use sockets etc).

In the case of more complex modules, where I want to allow different error cases to be caught separately I might define multiple exceptions, named on error semantics, but all prefixed with the module i.e. SomeModule<semantic_error>Exception - but again, the module methods/functions will always catch and wrap all exceptions from all modules it itself calls so you have a small finite list of exceptions you need to worry about.

Basically, I've taken exception handling and flattened it somewhat to make it easier to keep track of what exceptions can be thrown when/where and what I need to worry about handling.  It is still possible to dig into an exception and get the inner/cause exception, and theoretically I could alter my behaviour based on that, but I've never needed to yet.

All my exceptions come from a common base, except for certain "errors" which are only caught at top level locations i.e. process main, thread main, or the top of a conceptual "task" or task engine.  These are derived from a separate base type - much like we have Error and Exception in D - in fact, I probably got the idea from this NG :p

>> It would be nice if there was a mixin template that creates an
>> exception class that acts like this; making similar exception
>> classes is annoying.

+1 I use a macro in C++ for this.

Regan

-- 
Using Opera's revolutionary email client: http://www.opera.com/mail/
February 20, 2012
> 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" :}



February 20, 2012
"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.

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

So instead of solving a much more general problem with a clean definition-side-only solution, you'd rather tell people "Our langauge has 'throw' like any other modern langauge. Exept that many exceptions need to be used with this 'raise' thing instead of 'throw'."

Why do you keep optimizing for API creators at the expense of API users?


February 20, 2012
"dennis luehring" <dl.soluz@gmx.net> wrote in message news:jhtrh1$113l$1@digitalmars.com...
>> 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" :}
>

Exactly. It smacks of abandoning normal code in favor of JS and other such ultra-dynamic toy/scripting langauges where *everything* is a mutable AA just for the fuck of it.


February 20, 2012
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?