April 02, 2013
02-Apr-2013 14:37, deadalnix пишет:
> On Monday, 1 April 2013 at 11:08:16 UTC, Lars T. Kyllingstad wrote:
>> It's time to clean up this mess.
>>
>> http://wiki.dlang.org/DIP33
>
> Several things.
>
> First the usage of enums isn't the right path. This makes it hard to
> extend in general, and it is a poor man replacement for sub classes in
> general.

And using sub-classing just to tag something is equally bad. We don't have multiple inheritance so adding say 2 independent pieces of info can get devilishly hard (and lead to combinatorial explosion of classes).

What could be better is indeed "tags" that transport arbitrary set of interesting info about exception (that's what enums do but in more hard-wired way).

See also what C++ gurus come up with:
http://www.boost.org/doc/libs/1_53_0/libs/exception/doc/boost-exception.html

>
> As a rule of thumb, when you use switch in OOP code, you are likely to
> do something wrong.

And that's why? BTW D doesn't have pattern matching and type-switch like some OOP languages have.

You might want to add Visitor pattern to Exceptions but it's darn messy to deal with and is an overkill most of the time.

>
> Second, many of you error are recoverable here. It isn't quite satisfying.
>
> RangeError is a very bad thing IMO. It completely hides why the range
> fails in the first place. Trying to access front when not possible for
> instance, is an error for a reason (which is range dependent). That
> reason must be the source of the error/exception.

I/O error when in fact you just run out of range during some (bogus) algorithm  and that range happened to be backed by a MM-File? Think again.
>
> In general the hierarchy is weird. Why isn't NetworkingException (why
> not NetworkException ?) a subclass of IOException ?
>

No, no and no. I/O is read/write etc. calls. Network is broad stuff dealing at conceptually lower level (like discovering hosts that then would produce end-points that in turn can be connected to and only *then* I/O comes). "Unreachable host" is not an I/O error.

> OutOfMemoryError on its own isn't good IMO. The Error hierarchy is made
> for error that aren't recoverable (or may not be recoverable). It
> include a whole class of problem, and OOM is only one of them (another
> example is Stack overflow errors).


-- 
Dmitry Olshansky
April 02, 2013
On 4/2/13 7:24 AM, Dmitry Olshansky wrote:
> You might want to add Visitor pattern to Exceptions but it's darn messy
> to deal with and is an overkill most of the time.

Actually I think that's a good thing to do.

Andrei
April 02, 2013
On Monday, 1 April 2013 at 20:58:26 UTC, Walter Bright wrote:
> On 4/1/2013 4:08 AM, Lars T. Kyllingstad wrote:
>> It's time to clean up this mess.
>
>
> As for why finally blocks are not executed for Error exceptions, the idea is to minimize cases where the original error would now cause an abort during the unwinding process. Catching an Error is useful for things like:
>
> 1. throw the whole plugin away and restart it
> 2. produce a log of what happened before aborting
> 3. engage the backup before aborting
> 4. alert the operator that the system has failed and why before aborting
>
> Unwinding is not necessary for these, and can even get in the way by causing other failures and aborting the program by attempting cleanups when the code is in an invalid state.

I think that view is reasonable, but then I don't understand the reason to have Error in the first place! Why not just call some kind of abort() function, and provide the ability to hook into it?

BTW, I actually went to quite a lot of trouble to make stack unwinding work correctly for Errors on Windows. It really wasn't easy.
April 02, 2013
On Tuesday, 2 April 2013 at 11:42:01 UTC, Don wrote:
> I think that view is reasonable, but then I don't understand the reason to have Error in the first place! Why not just call some kind of abort() function, and provide the ability to hook into it?

I actually support something like this. While adding hooks for an non-recoverable error conditions is a valid use-case, it is better to keep it explicitly separate from usual error (exception) handling framework to keep clear that it is an advanced tool and hardly @safe.
April 02, 2013
02-Apr-2013 15:35, Andrei Alexandrescu пишет:
> On 4/2/13 7:24 AM, Dmitry Olshansky wrote:
>> You might want to add Visitor pattern to Exceptions but it's darn messy
>> to deal with and is an overkill most of the time.
>
> Actually I think that's a good thing to do.
>

Why would be that? It doesn't solve the key problem of "try clause plus a ton of semi-identical catches" used just to perform a mapping of X handlers to Y subsets of errors. Plus visitor does the same dispatch that is already addressed by exception handlers (or partly so).

If somebody comes up with a reasonable Visitor pattern for Exceptions that is flexible and fast then sure let's see it. I just doubt it'll help anything on its own in any case.

-- 
Dmitry Olshansky
April 02, 2013
On 4/1/13, Walter Bright <newshound2@digitalmars.com> wrote:
> On 4/1/2013 4:08 AM, Lars T. Kyllingstad wrote:
>> It's time to clean up this mess.
>
>
> As for why finally blocks are not executed for Error exceptions

They seem to be executed:

void main()
{
    try
    {
        throw new Error("");
    }
    finally
    {
        assert(0);
    }
}

This will throw an AssertError.
April 02, 2013
On Tue, Apr 02, 2013 at 08:55:43AM +0200, Jacob Carlborg wrote:
> On 2013-04-02 01:52, Steven Schveighoffer wrote:
[...]
> >But I also hate having to duplicate catch blocks.  The issue is that class hierarchies are almost never expressive enough.
> >
> >contrived example:
> >
> >class MyException : Exception {}
> >class MySpecificException1 : MyException {}
> >class MySpecificException2 : MyException {}
> >class MySpecificException3 : MyException {}
> >
> >try
> >{
> >    foo(); // can throw exception 1, 2, or 3 above
> >}
> >catch(MySpecificException1 ex)
> >{
> >    // code block a
> >}
> >catch(MySpecificException2 ex)
> >{
> >    // code block b
> >}
> >
> >What if code block a and b are identical?  What if the code is long and complex?  Sure, I can put it in a function, but this seems superfluous and verbose -- exceptions are supposed to SIMPLIFY error handling, not make it more complex or awkward.  Basically, catching exceptions is like having an if statement which has no boolean operators.
> >
> >Even if I wanted to write one block, and just catch MyException, then check the type (and this isn't pretty either), it's not exactly what I want -- I will still catch Exception3.  If this is the case, I'd rather just put an enum in MyException and things will be easier to read and write.
> 
> The obvious solution to that would be to be able to specify multiple exception types for a single catch block:
> 
> catch (MySpecificException1, MySpecificException2 ex)
> {
> }
[...]

But what type will ex be, inside the catch block?


T

-- 
Государство делает вид, что платит нам зарплату, а мы делаем вид, что работаем.
April 02, 2013
On 4/2/13 7:59 AM, Dmitry Olshansky wrote:
> 02-Apr-2013 15:35, Andrei Alexandrescu пишет:
>> On 4/2/13 7:24 AM, Dmitry Olshansky wrote:
>>> You might want to add Visitor pattern to Exceptions but it's darn messy
>>> to deal with and is an overkill most of the time.
>>
>> Actually I think that's a good thing to do.
>>
>
> Why would be that? It doesn't solve the key problem of "try clause plus
> a ton of semi-identical catches" used just to perform a mapping of X
> handlers to Y subsets of errors. Plus visitor does the same dispatch
> that is already addressed by exception handlers (or partly so).

Visitor allows centralized and flexible handling of exceptions.

> If somebody comes up with a reasonable Visitor pattern for Exceptions
> that is flexible and fast then sure let's see it. I just doubt it'll
> help anything on its own in any case.

Well I think exceptions + factory + visitor is quite the connection.


Andrei
April 02, 2013
On Tue, 02 Apr 2013 02:55:43 -0400, Jacob Carlborg <doob@me.com> wrote:

> The obvious solution to that would be to be able to specify multiple exception types for a single catch block:
>
> catch (MySpecificException1, MySpecificException2 ex)
> {
> }

Yes, this could help.  But it's still not great.  One must still store a "type identifier" in the ex, or have to deal with casting to figure out what type ex is.

It also promotes creating a new type for every single catchable situation.

Consider that we could create one exception type that contains an 'errno' member, and if we have the ability to run extra checks for catching you could do:

catch(ErrnoException ex) if (ex.errno == EBADF || ex.errno == EBADPARAM)
{
   ...
}

But if we must do it with types, we need:

class ErrnoException(uint e) : Exception
{
   enum errno = e;
}

or worse, to make things easier to deal with we have:

class ErrnoException : Exception
{
   int errno;
   this(int errno) { this.errno = errno; }
}

class ErrnoExceptionT(uint e) : ErrnoException
{
   this() { super(e); }
}

which would be easier to deal with, but damn what a waste!  Either way, every time you catch another errno exception, we are talking about instantiating another type.

I think the solution with a categorical errno exception, with a simple errno stored as a variable (along with the ability to catch based on it) is much cleaner IMO, and I wonder if testing members instead of typeids might be more efficient in the stack unwinding code.

-Steve
April 02, 2013
On Tuesday, 2 April 2013 at 12:18:00 UTC, Andrej Mitrovic wrote:
> On 4/1/13, Walter Bright <newshound2@digitalmars.com> wrote:
>> On 4/1/2013 4:08 AM, Lars T. Kyllingstad wrote:
>>> It's time to clean up this mess.
>>
>>
>> As for why finally blocks are not executed for Error exceptions
>
> They seem to be executed:
>
> void main()
> {
>     try
>     {
>         throw new Error("");
>     }
>     finally
>     {
>         assert(0);
>     }
> }
>
> This will throw an AssertError.

The spec makes no such guarantee, DMD just doesn't bother to not execute it. It is one of the many things which will break code when DMD decides to follow the spec.