January 26, 2006
nick wrote:
> Keeping it brief:
> 
> Shouldn't exception catching be mandatory as in Java?
> 
> If not, then shouldn't functions/methods still have a throws keyword so coders know what to catch?
> 
> Sorry if this has already been discussed.
> 


For every person who appreciates 'throws', there's another who loathes them. Turns out that programmers are (surprise!) mostly lazy, and tend to wrap a "catchall" around code that javac complains about. Anders (of C# fame) had a lot to say about this aspect, and made some compelling arguments. I understand Gosling has had his doubts upon reflection also.

There are a variety of reasons why one would abuse 'throws' (ranging from corporate-pressure to laziness to delusions), and a few that might encourage compliance (purity, 'correctness', long-term management). Which are more motivational in the general case? It doesn't help that a workable 'throws' design often requires ongoing and significant refactoring.

The other thing to consider is that D has a different philosophy in terms of 'correctness' enforcement ~ you won't even find a requirement to use the 'override' keyword in the appropriate manner :-D
January 26, 2006
>There are a variety of reasons why one would abuse 'throws' (ranging from corporate-pressure to laziness to delusions), and a few that might encourage compliance (purity, 'correctness', long-term management).

Shouldn't languages target those who want to write clean, workable code?
A langauge shouldn't try to accomodate bad programming practices; that's just
backwards.




January 26, 2006
"nick" <nick_member@pathlink.com> wrote..
> >There are a variety of reasons why one would abuse 'throws' (ranging
>>from corporate-pressure to laziness to delusions), and a few that might
>>encourage compliance (purity, 'correctness', long-term management).
>
> Shouldn't languages target those who want to write clean, workable code?

Sure they should. But if/when that becomes abused, it can create a worse situation than the initial state.


> A langauge shouldn't try to accomodate bad programming practices; that's
> just
> backwards.

Would seem that way.

Take a look at the bugs inherent within software, and compare that to hardware. We, as educated and technically capable people, take it for granted when supposedly solid products from the "best software companies in the world" fall over. Yet we scream bloody murder when, say, Intel leaves a bug in their floating point hardware. Why is that?

There's a distinct difference in mentality here. Both in the perception of the flaw, and in the propogation of the acceptability. One might be tempted to speculate that hardware companies and employees are "engineers who care about quality, robustness, and dependability". What would one say about software companies in comparison?

The upshot is that any language that enforces an 'ideology' is often targeted as a scapegoat, and gains little traction or adoption. Sure, that kind of attitude is full of double-standards and advocates of dubious persuasion. But that's the current climate in software development (IMO).

Heck ~ guess what the predominant pushback against 'mandatory override' was, in this very NG? Would you believe "too much typing"? Apparently, people felt that (when overriding a method) the effort of having to type an additional 8 characters, plus a space, far outweighed the benefits of doing so.




January 26, 2006
nick wrote:
>> There are a variety of reasons why one would abuse 'throws' (ranging 
>>from corporate-pressure to laziness to delusions), and a few that might 
>> encourage compliance (purity, 'correctness', long-term management). 
> 
> Shouldn't languages target those who want to write clean, workable code?
> A langauge shouldn't try to accomodate bad programming practices; that's just
> backwards.

Perhaps not, but it's arguable whether the lack of throw specs constitutes a "bad programming practice."  One thing I don't like about  throw specs is that they necessarily tie interface to implementation, which can leave library designers with the difficult choice of whether to change their throw spec if the implementation changes (and thus require all clients to update their code accordingly... which may be an enormous task), or to wrap implementation-specific exceptions before rethrowing them to the client.  The first case is probably the correct solution from an idealistic perspective, but it violates the interface stability contract that I believe libraries should adhere to.  The second case, however, masks the identity of the underlying exception, so automated error handling is impossible:

extern void doSomething() throws SomeException;

try {
    doSomething();
}
catch( SomeException e ) {
    // make sure a FatalException hasn't been wrapped
    // due to implementation changes
    for( Exception n = e.next; n; n = n.next )
    {
        // just an example, not entirely certain this does
        // what I'd like it to
        if( typeid( n ) == typeid( FatalException ) )
            throw n;
    }
    // do typical SomeException handling here
}

The solution I would likely choose is simply to have "throws Exception" as my throw spec, which is no different than what we have now.


Sean
January 26, 2006
Well I am all for mandatory override.
There should be - at least - a "good coder mode" that goes ahead and checks for
these things (perhaps a compiler flag). Do you think that's a practical thing to
expect from D?


January 26, 2006
In article <drbafg$1tdq$1@digitaldaemon.com>, Sean Kelly says...
>
>nick wrote:
>>> There are a variety of reasons why one would abuse 'throws' (ranging
>>>from corporate-pressure to laziness to delusions), and a few that might
>>> encourage compliance (purity, 'correctness', long-term management).
>> 
>> Shouldn't languages target those who want to write clean, workable code?
>> A langauge shouldn't try to accomodate bad programming practices; that's just
>> backwards.
>
>Perhaps not, but it's arguable whether the lack of throw specs constitutes a "bad programming practice."  One thing I don't like about
>  throw specs is that they necessarily tie interface to implementation,
>which can leave library designers with the difficult choice of whether to change their throw spec if the implementation changes (and thus require all clients to update their code accordingly... which may be an enormous task), or to wrap implementation-specific exceptions before rethrowing them to the client.  The first case is probably the correct solution from an idealistic perspective, but it violates the interface stability contract that I believe libraries should adhere to.  The second case, however, masks the identity of the underlying exception, so automated error handling is impossible:
>
>extern void doSomething() throws SomeException;
>
>try {
>     doSomething();
>}
>catch( SomeException e ) {
>     // make sure a FatalException hasn't been wrapped
>     // due to implementation changes
>     for( Exception n = e.next; n; n = n.next )
>     {
>         // just an example, not entirely certain this does
>         // what I'd like it to
>         if( typeid( n ) == typeid( FatalException ) )
>             throw n;
>     }
>     // do typical SomeException handling here
>}
>
>The solution I would likely choose is simply to have "throws Exception" as my throw spec, which is no different than what we have now.
>
>
>Sean

How would this scenario be better handled without a throw spec?


January 26, 2006
nick.atamas@gmail.com wrote:
> 
> How would this scenario be better handled without a throw spec?

Without a throw spec, the appropriate exception handler will always be called (assuming one exists).  Thus:

extern void doSomething() throws SomeException;

void trySomething() {
    try {
        doSomething();
    }
    catch( SomeException e ) {
        // handle e
    }
}

void main() {
    ...
    try {
        ...
        trySomething();
        ...
    }
    catch( FatalException e )
    {
        // handle e
    }
    ...
}

Here, the client already had a handler defined for FatalException, so when the implementation of doSomething changed to possibly throw it, the client didn't have to change anything.  I'll admit that in some cases the client may have wanted to handle this new exception at a lower level, or had no handler defined at all, but I'm not convinced that throw specs are the correct way to address this issue.

On a side note, the DDoc spec already contains "Throws" as a standard section, so there is some incentive to document this properly.


Sean
January 27, 2006
> [...SNIP...]
> but I'm not convinced that throw specs are the correct way to address this issue.
Right, so what is the correct way to address this issue?

> 
> On a side note, the DDoc spec already contains "Throws" as a standard section, so there is some incentive to document this properly.
That's good, but not good enough.

As far as I see it, there are 2 requirements:
(1) There must be an easy way to find out exactly what exceptions can be thrown
(2) There must be an automatic system that notifies the programmer if he is potentially running into trouble and letting some exceptions go uncaught.

Point 1 is addressed by the documentation.
Point 2 is not addressed at all by D.

Java addresses point 2 by using throw specs. This creates boilerplate code, but eclipse's refactoring facilities make this pretty much a non-issue.

So, what do you propose we do about Point 2?

January 27, 2006
"nick" <nick.atamas@gmail.com>
> Point 1 is addressed by the documentation.
> Point 2 is not addressed at all by D.
>
> Java addresses point 2 by using throw specs. This creates boilerplate code, but eclipse's refactoring facilities make this pretty much a non-issue.
>
> So, what do you propose we do about Point 2?

I'll propose that an IDE could trace the call-tree(s) and provide that information; perhaps on the fly. One might use the open-source D front-end to help implement such a system?


January 27, 2006
Well, I am going to try and bring this to Walter's attention. I think it's something that needs to be addressed. (Is there a process for this?)

You have made some fairly good arguments regarding the throws declaration, and I am convinced that it would be inappropriate to treat unhandled exceptions as errors - they should be warnings.

However, after doing some reading and thinking it has become apparent that exceptions ARE part of the interface, whether this interface is explicitly define via a throws spec or not. As such, I think it fitting to explicitly enforce this interface, or at least make the programmer very aware of it.

As far as the unfortunate case of try{}catch(Exception e){}, well that's just a programming no-no like using gotos and break where they don't absolutely belong.