www.digitalmars.com         C & C++   DMDScript  

D - Praise, Contract Programming, and Exceptions

reply Eric Gerlach <egerlach canada.com> writes:
Hello all,

(Author's note: This started out as a much shorter post that was meant 
to go in another thread... but it kept growing and growing, like Jack's 
beanstalk.)

First of all, Walter, I'd like to applaud you and your wonderful 
creation.  D is a language that shows some real promise as an industry 
standard.  I'm very, very excited about being able to try it eventually.

I think that above and beyond all the other improvements of the 
language, D's strongest feature is how it encourages robust programming. 
   Adding contracts (in/out/invariant) as a language construct is a 
great idea.  All too often a function that someone else writes doesn't 
do exactly what you thought it would for a boundary case, and having an 
easy way to know that it's their function and not your code screwing up 
would be wonderful.  I also love the idea of unit testing built into the 
classes.  In my experience, it won't get done well otherwise :)

However, I don't think D takes contracts far enough.  I think that all 
of a function's behaviour should be able to be described in the 
contract. Specifically, not having a 'throws' clause in a language that 
*encourages* throwing exceptions is suicide for the robustness that D 
appears to give.

I'm not going to reiterate all of the reasons to have 'throws' here, 
because I think they have been well enough stated in the threads: 
"throws?" and "Exception specification?"  But I am going to say that it 
is essential to providing the full and complete contract to a function.

When programming by contract, there are always 2 parties to the 
contract, the user and the implementor.  The implementor sets out a set 
of requirements and says "If these requirements are fulfilled, then I 
will do this!" and presents a set of results.  Breaking a contract goes 
two ways.  If the user does not meet the requirements, the contract is 
broken, and the implementor is under no obligation to fulfill it. 
However, if the implementor fails to finish the results, they have 
broken the contract, and the user will not be happy.

Now, let's take a rather funny hypothetical situation:  Implementors and 
users (the coders, not the code) will be fined $100 every time they 
break a contract.  Therefore, both implementors and users will want to 
keep their contracts all the time to avoid being fined.  But the 
implementors are in a bind.  Let's say that the 'connect()' function's 
contract says: "Call me, and I will connect to the server!"  What if the 
network is down?  It's not the connect() function's fault, but that 
coder will be fined because he broke the contract with the user.

Exceptions are the way out.  They allow an implementor to say: "Call me, 
and I will connect to the server EXCEPT if the network is down, or it's 
Tuesday!"  Now the implementor isn't held liable if the network is down. 
  Rejoice!  He doesn't get fined!

But without a 'throws' clause in a function declaration, the implementor 
isn't able to do this.  The 'connect()' function isn't able to give a 
complete contract to the world on how to use it.

The bottom line is that the 'throws' clause is necessary to provide 
complete contract programming.  If it isn't going to be in the language, 
you might as well get rid of all the contract programming constructs 
(in, out, invariant), as they lose much of their meaning, and only 
provide weak contracts.

Now, a disclaimer:  This is my only major plea about D.  I love the rest 
of the language.  If D catches on, it will be a Very Good Thing.

Cheers,

Eric

P.S. I'm going to make another post in a minute about some more ideas 
for exceptions
P.P.S. After that I'll make a post about a few more small things
Aug 25 2001
next sibling parent reply Eric Gerlach <egerlach canada.com> writes:
In anticipation of those that disagree with a semi-mandatory 'throws' 
clause, I'm going to take some arguments from a "better than C++" 
exception implementation, Java.

One of the concerns people have with making exceptions mandatory is the 
need to then either catch every possible exception, or specify it in 
your throws declaration.  Now while this is true, it's not such a bad 
thing.  Java deals with it nicely in two ways.

To understand the first method, read section 11.2 (including 11.2.1 and 
11.2.2) in the Java Language Speccification to be found at:

http://java.sun.com/docs/books/jls/second_edition/html/exceptions.doc.html#44121

(I strongly encourage reading the entire section 11, it's not that long)

Java allows RuntimeExceptions and Errors not to be declared in the 
throws, because those ones either are unidentifiable at compile time, or 
are serious and rare enough to bypass the decalaration rule.  All others 
must be, and I'd argue should be, based on my previous post.

The second method is documented in Java's documentation on Throwable:

http://java.sun.com/j2se/1.4/docs/api/java/lang/Throwable.html

There's a bit in the middle that talks about 'chaining' of exceptions, 
which allows an exception to know what exception caused it to be thrown. 
  Essentially what it allows is this (from the page):

try {
   lowLevelOp();
} catch LowLevelException(le) {
   throw new HighLevelException(le);  // Chaining-aware constructor
}

Then the code catching the HighLevelException(he) can call he.getCause() 
to get the LowLevelException.  That way, all sorts of low level network 
exceptions could be abstracted to NetworkException at a higher level 
with a chain down to the lower-level exception. Anyways, seek out that 
part and read it.  Good stuff.

I hope this addresses some of the concers that people have had with this 
clause in previous posts.

Cheers,

Eric
Aug 25 2001
parent reply "Bradeeoh" <bradeeoh crosswinds.net> writes:
I've been doing an INCREDIBLY large amount of Java programming lately, and I
just want to say that I knew this, and because of my experience with it,
know how invaluabl it is.  I want to second absolutely every thing you said
in your first post and the follow up and say that, indeed, the throws clause
is completely neccesary for real, complete contracted programming (or some
substitution thereof) and is even fairly critical outside of contracts (ie,
Java)

Of the many reasons programming in Java can go so much quicker and smoother,
I think the throws concept requiring Exceptions to be caught is one of them,
because the compiler KNOWS there may be an exception, and it doesn't let you
code without catching the exception and findout later after 2 days of
debugging it was that damned Exception all along when, if you were forced to
catch it, you would've figured it out in 3 seconds after trying to compile
your code without it.

<phew>

Anyway, long story short - throws = important and required, please include.
:)

-Brady


"Eric Gerlach" <egerlach canada.com> wrote in message
news:3B883583.1020802 canada.com...
 In anticipation of those that disagree with a semi-mandatory 'throws'
 clause, I'm going to take some arguments from a "better than C++"
 exception implementation, Java.

 One of the concerns people have with making exceptions mandatory is the
 need to then either catch every possible exception, or specify it in
 your throws declaration.  Now while this is true, it's not such a bad
 thing.  Java deals with it nicely in two ways.

 To understand the first method, read section 11.2 (including 11.2.1 and
 11.2.2) in the Java Language Speccification to be found at:

4121
 (I strongly encourage reading the entire section 11, it's not that long)

 Java allows RuntimeExceptions and Errors not to be declared in the
 throws, because those ones either are unidentifiable at compile time, or
 are serious and rare enough to bypass the decalaration rule.  All others
 must be, and I'd argue should be, based on my previous post.

 The second method is documented in Java's documentation on Throwable:

 http://java.sun.com/j2se/1.4/docs/api/java/lang/Throwable.html

 There's a bit in the middle that talks about 'chaining' of exceptions,
 which allows an exception to know what exception caused it to be thrown.
   Essentially what it allows is this (from the page):

 try {
    lowLevelOp();
 } catch LowLevelException(le) {
    throw new HighLevelException(le);  // Chaining-aware constructor
 }

 Then the code catching the HighLevelException(he) can call he.getCause()
 to get the LowLevelException.  That way, all sorts of low level network
 exceptions could be abstracted to NetworkException at a higher level
 with a chain down to the lower-level exception. Anyways, seek out that
 part and read it.  Good stuff.

 I hope this addresses some of the concers that people have had with this
 clause in previous posts.

 Cheers,

 Eric

Aug 25 2001
parent reply Dan Hursh <hursh infonet.isl.net> writes:
	Well, I don't want to say anything nice about java but I would like to
re-second this.  I would like to be able to look at a function and have
a reasonable idea of the error I need to be ready to handle.
	I wouldn't against having the default behavior (when there is no throws
clause) be that it can throw anything, so only the masochists need
declare what they are doing.  I do believe that any library that wants
to be taken seriously should, by convention, declare throws clauses for
every method.  This way folks who like to try to recover or clean up can
have some idea what can go wrong.  Otherwise I don't see how you could
do anything more that say 
	"I died because " + exception.msg();

Dan

Bradeeoh wrote:
 
 I've been doing an INCREDIBLY large amount of Java programming lately, and I
 just want to say that I knew this, and because of my experience with it,
 know how invaluabl it is.  I want to second absolutely every thing you said
 in your first post and the follow up and say that, indeed, the throws clause
 is completely neccesary for real, complete contracted programming (or some
 substitution thereof) and is even fairly critical outside of contracts (ie,
 Java)
 
 Of the many reasons programming in Java can go so much quicker and smoother,
 I think the throws concept requiring Exceptions to be caught is one of them,
 because the compiler KNOWS there may be an exception, and it doesn't let you
 code without catching the exception and findout later after 2 days of
 debugging it was that damned Exception all along when, if you were forced to
 catch it, you would've figured it out in 3 seconds after trying to compile
 your code without it.
 
 <phew>
 
 Anyway, long story short - throws = important and required, please include.
 :)
 
 -Brady
 
 "Eric Gerlach" <egerlach canada.com> wrote in message
 news:3B883583.1020802 canada.com...
 In anticipation of those that disagree with a semi-mandatory 'throws'
 clause, I'm going to take some arguments from a "better than C++"
 exception implementation, Java.

 One of the concerns people have with making exceptions mandatory is the
 need to then either catch every possible exception, or specify it in
 your throws declaration.  Now while this is true, it's not such a bad
 thing.  Java deals with it nicely in two ways.

 To understand the first method, read section 11.2 (including 11.2.1 and
 11.2.2) in the Java Language Speccification to be found at:

4121
 (I strongly encourage reading the entire section 11, it's not that long)

 Java allows RuntimeExceptions and Errors not to be declared in the
 throws, because those ones either are unidentifiable at compile time, or
 are serious and rare enough to bypass the decalaration rule.  All others
 must be, and I'd argue should be, based on my previous post.

 The second method is documented in Java's documentation on Throwable:

 http://java.sun.com/j2se/1.4/docs/api/java/lang/Throwable.html

 There's a bit in the middle that talks about 'chaining' of exceptions,
 which allows an exception to know what exception caused it to be thrown.
   Essentially what it allows is this (from the page):

 try {
    lowLevelOp();
 } catch LowLevelException(le) {
    throw new HighLevelException(le);  // Chaining-aware constructor
 }

 Then the code catching the HighLevelException(he) can call he.getCause()
 to get the LowLevelException.  That way, all sorts of low level network
 exceptions could be abstracted to NetworkException at a higher level
 with a chain down to the lower-level exception. Anyways, seek out that
 part and read it.  Good stuff.

 I hope this addresses some of the concers that people have had with this
 clause in previous posts.

 Cheers,

 Eric


Aug 26 2001
parent reply Eric Gerlach <egerlach canada.com> writes:
  Well, I don't want to say anything nice about java but I would like to
 re-second this.  I would like to be able to look at a function and have
 a reasonable idea of the error I need to be ready to handle.

I don't usually advocate Java either... I'm only half-pleased with their VM way of doing things, and am still not sure about the class library, it's complete, but as someonw mentioned, if you use one bit, you have to use all the bits. However, IMHO exception handling is one thing they got right.
 	I wouldn't against having the default behavior (when there is no throws
 clause) be that it can throw anything, so only the masochists need
 declare what they are doing.  I do believe that any library that wants
 to be taken seriously should, by convention, declare throws clauses for
 every method.  This way folks who like to try to recover or clean up can
 have some idea what can go wrong.  Otherwise I don't see how you could
 do anything more that say 
 	"I died because " + exception.msg();

Six months ago I would have been okay with it too, but working on the most recent project I've been working on, I can't say I'm okay with it anymore. The project was built in C++ through a series of grafts, and eventually emerged as a complete system. One of the annoying problems we've been having is that occasionally someone forgets to document an exception in a header file. The exceptional case occurs, and it throws. That exception propagates half-way up the call stack, and is caught in a really wierd place. Our exceptions don't know where they came from in code (another problem), and so you spend a while trying to figure out what part of your code threw that exception, and it ends up being annoying. There are three ways to handle a mandatory throws clause: 1) Don't throw exceptions :) 2) Document every specific exception that could be thrown (the Good Way) or 3) 'throws (Exception)' (the 'I'm Lazy') way. So, there is a way to get around a mandatory throws clause if you don't want to document every exception. At least that way people who call your function know you might throw *something*, but it won't be very meaningful. But, the whole point of meaningful exceptions is so that you can recover gracefully from them. Otherwise, you're right, all you get is: "I died because " + exception.msg(); Ow. I don't want my app doing that. Eric P.S. Idea: Exceptions should know what file and line they were thrown from by default.**
Aug 26 2001
parent "Sean L. Palmer" <spalmer iname.com> writes:
 P.S. Idea: Exceptions should know what file and line they were thrown
 from by default.**

Yes.
Nov 03 2001
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
Here's my problem with a throws clause:

A calls B
B calls C
C calls D

D is in some third party library. Now, D is updated to throw another
exception. Now, the code in C, B, and A all needs to be updated. To me, this
breaks code reuse.

-Walter
Aug 26 2001
next sibling parent reply Eric Gerlach <egerlach canada.com> writes:
Walter wrote:
 Here's my problem with a throws clause:
 
 A calls B
 B calls C
 C calls D
 
 D is in some third party library. Now, D is updated to throw another
 exception. Now, the code in C, B, and A all needs to be updated. To me, this
 breaks code reuse.
 
 -Walter

If you think about it, either way it breaks code reuse. In fact, changing *any* part of a contract breaks code reuse! If D changes his pre- or post-conditions, C is going to run into problems, because the 'assert(i<=5)' just became 'assert(i<5)', and he's counting on passing 5s! That isn't any reason to not include them in the language (as the language D so aptly demonstrates). Back to exceptions: If D adds a new exception, C, B, and A are broken anyways, because they don't know it's coming! I think having the clause breaks code reuse *less*, not more. Consider a stack of fixed size which used to perform a no-op if you tried to push beyond the limits of the stack. Well, the author decided that it wasn't good behaviour for the stack, and so now the push() method throws an exception. The stack is D. The author of C downloads the new version of D to run his unit tests (yay for unit tests) to make sure his still works. Now, one of several things happen based on whether there is a mandatory throws clause or not. Mandatory throws clause: C's code doesn't compile. "Damn," he says, and adds the five or so lines of code to catch and chain the exception. If he's not sure how to handle it, he has to think about it. No throws clause: Turns out C's unit tests weren't quite thorough, and he missed the boundary case where the exception would be thrown (C isn't a simple system). I'm the author of A. If there is a mandatory throws clause, I probably don't even notice that a new exception is there. A good programmer at the C or B level will catch and *handle* the exception as it should be handled. So with a throws clause I'm less likely to be affected at all. If I am affected, it will be that my code doesn't compile. No problem. I add a few lines and go merrily on my way. That is certainly preferable to the alternative, which occurs without a throws clause. I find out four months after deployment of my new software that the stupid author of D added an exception to his code which bubbled up to my code. Now I have to issue a patch and change all my code... But wait! I can't even catch the specific exception, because it's not in my scope! In fact, even if I catch a generic Exception, I can't handle it properly, because I have no idea what the innards of B, C, or D are! Even worse, I don't even know that it is D that is causing me problems!!! There is no way to fix this problem, except to contact the author of B, who after hours of searching finds the obscure case and contacts the author of C, who does the same and eventually the author of D is contacted who tells us all: "Oh yeah, I added an exception." What pisses me off more? Having to add three lines to catch a new exception from B because my code won't compile? (Which likely wouldn't happen) OR the horrible scenario I described in the last paragraph? I'd say I'd rather recompile than face that crap. My code is less *critially* broken if the throws clause is there, and mandatory. Now I can understand your reluctance to add it to the language if there is a good *compiler* reason to leave it out. But I think from a language architecture standpoint it's a good idea. Cheers, Eric
Aug 26 2001
parent reply Russell Bornschlegel <kaleja estarcion.com> writes:
Eric Gerlach wrote:
 
 Walter wrote:
 Here's my problem with a throws clause:

 A calls B
 B calls C
 C calls D

 D is in some third party library. Now, D is updated to throw another
 exception. Now, the code in C, B, and A all needs to be updated. To me, this
 breaks code reuse.

 -Walter

If you think about it, either way it breaks code reuse [...snippy...]

Eric, thanks for your excellent example here. I'd been leaning against throws-contracting out of laziness, and your argument is persuasive. (Hey, what are the interactions between C++ exceptions and D exceptions? Does propagation always stop at the language barrier?) I'd personally like to write code for quick-n-dirty tools without being concerned with exceptions at all. Can we define some solution wherein the default behavior is to not care what exceptions might be thrown? -RB
Aug 26 2001
next sibling parent reply "Walter" <walter digitalmars.com> writes:
Russell Bornschlegel wrote in message <3B89ECDD.1282D39D estarcion.com>...
(Hey, what are the interactions between C++ exceptions and
D exceptions? Does propagation always stop at the language
barrier?)

Since, in C++, you can throw any type, but in D, you can only throw class instances of a type that doesn't exist in C++, there's an obvious compatibility problem. One solution is to fake a wrapper around any incoming C++ exception, but I feel a better solution is to ignore the problem and assert that exceptions should not propagate across DLL or language boundaries.
I'd personally like to write code for quick-n-dirty tools without
being concerned with exceptions at all. Can we define some solution
wherein the default behavior is to not care what exceptions might
be thrown?

That might be best.
Aug 27 2001
parent "Sean L. Palmer" <spalmer iname.com> writes:
I'd personally like to write code for quick-n-dirty tools without
being concerned with exceptions at all. Can we define some solution
wherein the default behavior is to not care what exceptions might
be thrown?

That might be best.

Perhaps if the compiler detects exceptions that aren't handled, it might issue a warning... if you're just doing something quick and dirty, you could feel free to ignore this warning. I'm all in favor of forcing code to be more robust and reliable. So I guess I'm in favor of explicit throws() clauses, unless the compiler can detect this for me. Sean
Nov 03 2001
prev sibling parent reply Eric Gerlach <egerlach canada.com> writes:
 Eric, thanks for your excellent example here. I'd been leaning 
 against throws-contracting out of laziness, and your argument is 
 persuasive.

I try. :)
 I'd personally like to write code for quick-n-dirty tools without
 being concerned with exceptions at all.

The thing is, the language uses exceptions as its method of communicating errors. So no matter what you do, you're going to have exceptions to think about. If there were a mandatory 'throws' clause you could just have every function 'throws (Exception)' and you're fine. That is a bit ugly though. :(
 Can we define some solution
 wherein the default behavior is to not care what exceptions might 
 be thrown?

I'm not sure exactly what you mean by this. If you're referring to Dan Hursh's idea:
       void f() throws();		// I throw nothing
 	void g() throws(X, Y, Z)	// I throw X, Y & Z type exceptions
 	void h();			// I'm making no promises

Then that's what I'd call the minimum. What I glean from this is that if a function declaration has a 'throws' clause, then the compiler will check the body of that function to make sure that no other exceptions other than those declared could possibly be thrown. If there is no throws clause, there is no contract there. To be honest, that's not a bad solution when compared to the other contract mechanisms. Just as you are encouraged to use in, out, invariant and test blocks for your code, you'd be encouraged to use throws clauses too. One suggestion though: I think compiler warnings should be issued if there is the threat of exceptions being thrown in a function that doesn't have a throws clause. So the enforcement comes when you have warnings-as-errors and -Wall on, as many good applications do. Now, here's a challenge: design a language that *ennforces* the proper use of pre- and post- conditions, as well as class invariants. Damn that'd be neat. Eric
Aug 27 2001
next sibling parent Dan Hursh <hursh infonet.isl.net> writes:
Eric Gerlach wrote:
 Now, here's a challenge: design a language that *ennforces* the proper
 use of pre- and post- conditions, as well as class invariants.  Damn
 that'd be neat.
 
 Eric

That's scary. Do you mean it would make sure they are meaningful? If the compiler could do that, it wouldn't be to far away from writing your code for you. It reminds me of a feeble attempt a group at the university I went to tried. They wanted to design a language that would allow the programmer to define, in mathematics notion, what a piece of code was supposed to do using pre & post conditions, requires & returns clauses, assume & invariant statements and the like for each routine, function, module and loop. The compiler has to understand graph theory and turning theory. It amounted to the programmer writing the code once as an interface description and again as real code. The idea being that you could swap implementation as long as the compiler agreed that it still fit the mathematic interface description. They tried to graft this monstrosity onto C++ (it was the only way they would switch from teaching Modula-2) and taught it to a few years of students who thought they were being taught straight C++. I was pretty decent a C++ at the time, but I could not read the code at all. They made up dozens of new keywords that just didn't fit. The library was made so the students had to have 10-20 MB of quota to compile the most trivial of programs. The compiler required all of those contract declarations but I don't think they ever amounted to being anything more that required comments. The compiler logic was too complicated to actually use them for validity checking. I've heard rumors that they were going to try grafting this thing on scheme and java. I believe the C++ implementation was considered a loss. Getting back to you suggestion, it's not that the idea isn't neat and the intentions I'm sure are good, but it gives me flashbacks. A Prof.'s research should never be taught as a standard before it has been proven (or falls on it's face). Dan
Aug 27 2001
prev sibling next sibling parent reply Chris Friesen <chris_friesen sympatico.ca> writes:
Eric Gerlach wrote:

 Then that's what I'd call the minimum.  What I glean from this is that
 if a function declaration has a 'throws' clause, then the compiler will
 check the body of that function to make sure that no other exceptions
 other than those declared could possibly be thrown.  If there is no
 throws clause, there is no contract there.

So then the compiler has to construct some kind of lookup table as to what exceptions each function with a 'throws' clause in the entire system (including all the libraries that you use) can throw. In a large system I could imagine this taking a LOT of memory to keep track of. I'm all for it, but it's going to cost us. Chris
Aug 27 2001
parent reply Eric Gerlach <egerlach canada.com> writes:
 So then the compiler has to construct some kind of lookup table as to what
 exceptions each function with a 'throws' clause in the entire system (including
 all the libraries that you use) can throw.  In a large system I could imagine
 this taking a LOT of memory to keep track of.

I'm not sure that's true. As I'm going over the parse tree, when in a function that has a throws clause I check to see if it has any function calls inside which have throws clauses themselves. If I find one, and it isn't caught or declared in that scope, I print out an error and die. If there's anything to keep track of, it's no bigger than parameter declarations anyways. The record of 'who throws what' shouldn't have to carry over to runtime, as it will have already been checked and verified. Of course, that is only the case if we can't speed up execution by having it. Eric
Aug 27 2001
parent reply Dan Hursh <hursh infonet.isl.net> writes:
Eric Gerlach wrote:
 
 So then the compiler has to construct some kind of lookup table as to what
 exceptions each function with a 'throws' clause in the entire system (including
 all the libraries that you use) can throw.  In a large system I could imagine
 this taking a LOT of memory to keep track of.

I'm not sure that's true. As I'm going over the parse tree, when in a function that has a throws clause I check to see if it has any function calls inside which have throws clauses themselves. If I find one, and it isn't caught or declared in that scope, I print out an error and die. If there's anything to keep track of, it's no bigger than parameter declarations anyways. The record of 'who throws what' shouldn't have to carry over to runtime, as it will have already been checked and verified. Of course, that is only the case if we can't speed up execution by having it. Eric

Actually, when in a function with a throws clause, you have to check all the functions, even the once without a throws clause. You are making a promise even if the functions you call don't. Basically I would assume a function without a throws clause is implying he throws the exception base class. On a related note, how will this affect virtual method calls? Does this mean that if you override a method you can only have a throws clause containing the same types as your base class or your exceptions have to be subclasses of the exceptions you parent throws? I would assume so, but is this reasonable in practice? Do throws clauses get attached to interface signatures? Again, I think so and I do know if this is reasonable. It sounds like it would require though on the behave of interface and class designers so that they don't paint folks into a corner. BTW. I'm still in favor of having throws clauses and enforcing them. Dan
Aug 27 2001
parent Eric Gerlach <egerlach canada.com> writes:
 Actually, when in a function with a throws clause, you have to check
 all the functions, even the once without a throws clause.  You are
 making a promise even if the functions you call don't.  Basically I
 would assume a function without a throws clause is implying he throws
 the exception base class.

Well, if *all* the functions had mandatory throws clauses that wouldn't be a problem now would it? :)) I never did think of that though. OTOH, it couldn't be that big could it? I mean, all of the function's parameters have to be kept in a table somewhere... would exceptions take that much more room?
 	On a related note, how will this affect virtual method calls?  Does
 this mean that if you override a method you can only have a throws
 clause containing the same types as your base class or your exceptions
 have to be subclasses of the exceptions you parent throws?  I would
 assume so, but is this reasonable in practice?  Do throws clauses get
 attached to interface signatures?  Again, I think so and I do know if
 this is reasonable.  It sounds like it would require though on the
 behave of interface and class designers so that they don't paint folks
 into a corner.

To be honest, I was thinking about this and I couldn't figure it out either. So I just went and checked what Java does: "A method that overrides or hides another method (8.4.6), including methods that implement abstract methods defined in interfaces, may not be declared to throw more checked exceptions than the overridden or hidden method. More precisely, suppose that B is a class or interface, and A is a superclass or superinterface of B, and a method declaration n in B overrides or hides a method declaration m in A. If n has a throws clause that mentions any checked exception types, then m must have a throws clause, and for every checked exception type listed in the throws clause of n, that same exception class or one of its superclasses must occur in the throws clause of m; otherwise, a compile-time error occurs." So it would seem that your conception isn't ludicrous. I think that it makes sense, because you have to maintain the guarantee that users of the superclass expect. If the body of your function (in the subclass) could throw another exception, well, good coding practice would dictate you should be handling that internally, rather than breaking the contract set out by your parent. Eric
Aug 28 2001
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
Eric Gerlach wrote in message <3B8AE63F.4010400 canada.com>...
One suggestion though:  I think compiler warnings should be issued if
there is the threat of exceptions being thrown in a function that
doesn't have a throws clause.  So the enforcement comes when you have
warnings-as-errors and -Wall on, as many good applications do.

One thing I haven't mentioned in the docs, but is a design goal, is to not have warnings. Code should compile or it should fail with a diagnostice message. I dislike getting a piece of code from somewhere, running the makefile, and getting a bunch of warnings. Was I compiling the code right? Are those warnings real bugs or not? Why did whoever wrote the code ignore the warnings? Etc. If you examine the warnings C compilers give, it is usually to make up for some weakness in the language. I've tried to address those weaknesses, and thereby getting rid of the warnings.
Now, here's a challenge: design a language that *ennforces* the proper
use of pre- and post- conditions, as well as class invariants.  Damn
that'd be neat.

But I still want to be able to just bang out sloppy code for a one-shot purpose. Some programming jobs are worth doing but not worth doing well <g>.
Aug 28 2001
parent reply Eric Gerlach <egerlach canada.com> writes:
 Eric Gerlach wrote in message <3B8AE63F.4010400 canada.com>...
 
One suggestion though:  I think compiler warnings should be issued if
there is the threat of exceptions being thrown in a function that
doesn't have a throws clause.  So the enforcement comes when you have
warnings-as-errors and -Wall on, as many good applications do.

One thing I haven't mentioned in the docs, but is a design goal, is to not have warnings. Code should compile or it should fail with a diagnostice message. I dislike getting a piece of code from somewhere, running the makefile, and getting a bunch of warnings. Was I compiling the code right? Are those warnings real bugs or not? Why did whoever wrote the code ignore the warnings? Etc. If you examine the warnings C compilers give, it is usually to make up for some weakness in the language. I've tried to address those weaknesses, and thereby getting rid of the warnings.

I thought that might be the case due to how you deal with what used to be local variable warnings. Well, if that's your reasoning for removing compiler warnings, I think the throws clause should be mandatory. Essentially, if you're making all warnings errors by default, you're trying to have the language clean up people's sloppy code. I think this is a Good Thing. However, not bothering to declare exceptions is sloppy code. People should be at least warned if their functions might throw an exception. Heck, I'd like to be. When I was doing programming competitions a few years back, we'd have a Pascal file that started with: var a, b, c, i, j, k, l, m, n, q, x, y, z : Integer; The reason was we didn't want to spend time thinking about variable definitions. It's sloppy, yes, but we just wanted to bang out some code quickly. In C, this would have caused warnings. In D, this would cause an error. D can't let people get away with being sloppy in some areas but not in others. If D is going to crack down on sloppy code from programmers, then it should be as ruthless with exceptions as it is about all other aritifacts of sloppy code. Now, the argument has been made: "Sometimes I want to bang out code quick without regard to exceptions." Well, how about without regard to local variables? Signed/unsigned comparisons? (which I assume will become an error as well... as it is typically a warning) All these things are marks of sloppy coding. If they're warnings, then you get the problems described above by Walter. If they're errors, you can't bang out quick code. Perhaps what the compiler needs is to make a category of errors known as 'non-fatal' errors. i.e. If you have one your code will still run, but it may not run well. Then, add a '-sloppy' or like switch to the compiler, which lets it behave leniantly with regard to these errors. Now you have the tight checking for production-level code, and you have the leniant mode to allow for quick, dirty work. Not to mention, you have to explicitly invoke the sloppy mode, so the majority of code will be clean. Personally, I think that solution works great. Gives flexibility of C when you need it, but is usually very strict like Java. The best of both worlds!
Now, here's a challenge: design a language that *ennforces* the proper
use of pre- and post- conditions, as well as class invariants.  Damn
that'd be neat.

But I still want to be able to just bang out sloppy code for a one-shot purpose. Some programming jobs are worth doing but not worth doing well <g>.

Oh goodness! I didn't mean *do* it.... I just meant it would be a challenge. Any takers? :)
Aug 28 2001
next sibling parent reply "Walter" <walter digitalmars.com> writes:
Eric Gerlach wrote in message <3B8C30BB.2060805 canada.com>...
Now, the argument has been made:  "Sometimes I want to bang out code
quick without regard to exceptions."  Well, how about without regard to
local variables?  Signed/unsigned comparisons? (which I assume will
become an error as well... as it is typically a warning)  All these
things are marks of sloppy coding.  If they're warnings, then you get
the problems described above by Walter.  If they're errors, you can't
bang out quick code.

Oh, so you want me to be consistent? <g> <harrumph>
Perhaps what the compiler needs is to make a category of errors known as
'non-fatal' errors.  i.e. If you have one your code will still run, but
it may not run well.  Then, add a '-sloppy' or like switch to the
compiler, which lets it behave leniantly with regard to these errors.

Every compiler switch is a bug.
Aug 28 2001
next sibling parent reply Eric Gerlach <egerlach canada.com> writes:
 Eric Gerlach wrote in message <3B8C30BB.2060805 canada.com>...
 
Now, the argument has been made:  "Sometimes I want to bang out code
quick without regard to exceptions."  Well, how about without regard to
local variables?  Signed/unsigned comparisons? (which I assume will
become an error as well... as it is typically a warning)  All these
things are marks of sloppy coding.  If they're warnings, then you get
the problems described above by Walter.  If they're errors, you can't
bang out quick code.

Oh, so you want me to be consistent? <g> <harrumph>

eep! OfcourseI'mnotpresumingtoimposeonyouinanymannerwhatsoeverIsimplybelievethattheconceptsa emutuallyexclusive. Pleasedon'tkillmeohgreatlanguagedesignersir. :)
Perhaps what the compiler needs is to make a category of errors known as
'non-fatal' errors.  i.e. If you have one your code will still run, but
it may not run well.  Then, add a '-sloppy' or like switch to the
compiler, which lets it behave leniantly with regard to these errors.

Every compiler switch is a bug.

I think that's over-generalisation. For example, you've described several compiler switches. Are they bugs? There are some decisions that have to be made at the compiler level, and not at the code level. One such example is whether to generated debug symbols or not, another is code optimisation. You have to have compiler switches for those. I think that relaxing the errors that are only there for code-style enforcement should be another one. There are obviously two ways of writing code: the strict way, and the loose way. I think that D tends towards the strict way, so make it go all the way by default, and allow programmers to loosen it up if they want. Really, it doesn't matter how, I just thought a compiler switch was appropriate. Eric
Aug 29 2001
parent "Walter" <walter digitalmars.com> writes:
Eric Gerlach wrote in message <3B8D8D13.4090609 canada.com>...
Perhaps what the compiler needs is to make a category of errors known as
'non-fatal' errors.  i.e. If you have one your code will still run, but
it may not run well.  Then, add a '-sloppy' or like switch to the
compiler, which lets it behave leniantly with regard to these errors.


several compiler switches. Are they bugs? There are some decisions that have to be made at the compiler level, and not at the code level. One such example is whether to generated debug symbols or not, another is code optimisation. You have to have compiler switches for those.

Yes, of course. I was referring to the idea that compiling a program should be as simple as running the compiler. You shouldn't have to consult a thick manual to figure out the plethora of switches. Look at C/C++ programming. Ever see a makefile without a looong list of switches that change the language being compiled, add layers of explicit and implicit #define's, etc.?
I think that relaxing the errors that are only there for code-style
enforcement should be another one.  There are obviously two ways of
writing code: the strict way, and the loose way.  I think that D tends
towards the strict way, so make it go all the way by default, and allow
programmers to loosen it up if they want.  Really, it doesn't matter
how, I just thought a compiler switch was appropriate.

One issue with this idea is having multiple incompatible builds of, say, a library.
Sep 01 2001
prev sibling parent reply Dan Hursh <hursh infonet.isl.net> writes:
Walter wrote:
 Every compiler switch is a bug.

Especially that '-o' one. If it ain't called a.out, I ain't runnin' it! :-)
Aug 29 2001
parent reply "Walter" <walter digitalmars.com> writes:
Dan Hursh wrote in message <3B8DAED3.630B4D97 infonet.isl.net>...
Walter wrote:
 Every compiler switch is a bug.

Especially that '-o' one. If it ain't called a.out, I ain't runnin' it! :-)

-o is a bug. After all, the compiler should be smart enough to figure out that if you compile foo.c, the resulting executable should be named foo (or foo.exe for win32).
Sep 01 2001
parent "Angus Graham" <agraham_d agraham.ca> writes:
"Walter" <walter digitalmars.com> wrote:

 -o is a bug. After all, the compiler should be smart enough to figure out
 that if you compile foo.c, the resulting executable should be named foo

 foo.exe for win32).

So make sure not to call any files win.c! :-) "Hello tech support? When I turn on my computer it only says 'Hello World!'" Angus
Sep 02 2001
prev sibling parent "John Carney" <john.carney pacific.net.au> writes:
<snip>

 Now, the argument has been made:  "Sometimes I want to bang out code
 quick without regard to exceptions."  Well, how about without regard to
 local variables?  Signed/unsigned comparisons? (which I assume will

Type safety? Encapsulation? The list goes on...
Aug 29 2001
prev sibling next sibling parent reply Dan Hursh <hursh infonet.isl.net> writes:
Walter wrote:
 
 Here's my problem with a throws clause:
 
 A calls B
 B calls C
 C calls D
 
 D is in some third party library. Now, D is updated to throw another
 exception. Now, the code in C, B, and A all needs to be updated. To me, this
 breaks code reuse.
 
 -Walter

You are right, but I consider it a side affect of the interface of D changing. I be upset if the number or types of parameter to D changed and the compiler didn't flag that. Throwing a new type of exception is like changing the type of a parameter. One of my big problems with errno is that platforms can make up their own values. They can change them add them remove and I would never know and hence I cannot even attempt to handle in any way except to ignore them or throw my hands up and abort. So you right, it a pain, but it's D's fault for changing the API. Error conditions should be a part of a good API. If A want's he can be lazy and just have a throws clause of Exception or what ever the exception base class is. You could also pick up the syntax: void f() throws(); // I throw nothing void g() throws(X, Y, Z) // I throw X, Y & Z type exceptions void h(); // I'm making no promises I think libraries should document their errors with throws clauses, but I wouldn't want the language to enforce that. Dan
Aug 26 2001
parent reply "John Carney" <john.carney pacific.net.au> writes:
<snip>

 You are right, but I consider it a side affect of the interface of D
 changing.  I be upset if the number or types of parameter to D changed
 and the compiler didn't flag that.  Throwing a new type of exception is
 like changing the type of a parameter.  One of my big problems with
 errno is that platforms can make up their own values.  They can change
 them add them remove and I would never know and hence I cannot even
 attempt to handle in any way except to ignore them or throw my hands up
 and abort.
 So you right, it a pain, but it's D's fault for changing the API.
 Error conditions should be a part of a good API.  If A want's he can be
 lazy and just have a throws clause of Exception or what ever the

Amen.
 exception base class is.  You could also pick up the syntax:

 void f() throws(); // I throw nothing
 void g() throws(X, Y, Z) // I throw X, Y & Z type exceptions
 void h(); // I'm making no promises

I'd much rather require that a method without an exception contract state it explicitly: void f() ; // I throw nothing void g() throws (X, Y, Z) ; // I throw X, Y & Z void h() throws anything ; // Warning! Warning! Lazy programmer ;-)
 I think libraries should document their errors with throws clauses, but
 I wouldn't want the language to enforce that.

Can I ask a question of everybody on this thread? How many of you have actually spent anytime working with a language that has rigorous exception specification syntax (eg. Java)? I spent 18 months programming almost exclusively in Java and I honestly did not find having to declare exceptions a bother. As for API drift being a problem in this regard, it happens a hell of a lot less than you might imagine - and when it does happen, you can relax in the certain knowledge that you're compiler's going to tell you about each and every point at which changes in a 3rd party library has broken your code. Regards, John Carney.
Aug 28 2001
next sibling parent reply Dan Hursh <hursh infonet.isl.net> writes:
John Carney wrote:
 exception base class is.  You could also pick up the syntax:

 void f() throws(); // I throw nothing
 void g() throws(X, Y, Z) // I throw X, Y & Z type exceptions
 void h(); // I'm making no promises

I'd much rather require that a method without an exception contract state it explicitly: void f() ; // I throw nothing void g() throws (X, Y, Z) ; // I throw X, Y & Z void h() throws anything ; // Warning! Warning! Lazy programmer ;-)

But this seems to defeat the lazy programer's purpose. He's LAZY. He doesn't want to have to declare that he's not declaring something. That one of the things I find amusingly correct about perl's requirement that programmer who want to be forced to declare variables, have to declare that they want to have to declare variables. The lazy programmer does nothing and gets the behavior that benefits lazy programmers. It's poetic in nature.
 I think libraries should document their errors with throws clauses, but
 I wouldn't want the language to enforce that.

Can I ask a question of everybody on this thread? How many of you have actually spent anytime working with a language that has rigorous exception specification syntax (eg. Java)? I spent 18 months programming almost exclusively in Java and I honestly did not find having to declare exceptions a bother.

Java is a VM. There's a difference.
 As for API drift being a problem in this regard, it happens a hell
 of a lot less than you might imagine - and when it does happen, you can
 relax in the certain knowledge that you're compiler's going to tell you
 about each and every point at which changes in a 3rd party library has
 broken your code.

API drift may not happen much, but platform differences are another matter. That's one reason why errno can be ugly. With some many standard to choose from, which ones do you pick and how closely do you stick to each one. Vendors like to deviate from specs in order to accentuate their advantages in cases where specs try to pick least common denominators. Different implementation allow for different error conditions. With Java you have one platform, the JVM, and it is only liable to change every six months or however often Sun decides to mess with the world. When compiling to something less standard, say native operation systems, you have room for a lot more differences. This would have a bad gut feeling to anyone who has had to deal with portability a lot. You now have API drift for several different platforms, and they don't even happen at the same time. Now, I still agree that throws clauses should be in. It will be easier for API designer's to declare IN BLOOD the classes of errors that the developer should have to worry about. Provided that the API developers exercise on ounce of forethought, it should be possible to provide a setup of exception classes that covers the least common denominators, with giving platform vendors the ability to provide platform specific subclasses for better error granularity for those you want to tie themselves to a single platform or like to use conditional compilation. Provided that you give in to letting lazy tools programmer not declare any throws clause and get the lazy behavior of passing on all exceptions, they should have nothing to complain about. It will only impact implementors of compilers and libraries. I guess anyone writing a code analyzer might care too. Dan
Aug 28 2001
parent reply "John Carney" <john.carney pacific.net.au> writes:
"Dan Hursh" <hursh infonet.isl.net> wrote in message
news:3B8C760E.72C63D32 infonet.isl.net...
 John Carney wrote:
 exception base class is.  You could also pick up the syntax:

 void f() throws(); // I throw nothing
 void g() throws(X, Y, Z) // I throw X, Y & Z type exceptions
 void h(); // I'm making no promises

I'd much rather require that a method without an exception contract


 explicitly:

     void f() ;    // I throw nothing
     void g() throws (X, Y, Z) ; // I throw X, Y & Z
     void h() throws anything ; // Warning! Warning! Lazy programmer ;-)

But this seems to defeat the lazy programer's purpose. He's LAZY. He doesn't want to have to declare that he's not declaring something. That one of the things I find amusingly correct about perl's requirement that programmer who want to be forced to declare variables, have to declare that they want to have to declare variables. The lazy programmer does nothing and gets the behavior that benefits lazy programmers. It's poetic in nature.

<sigh> The problem is that lazy programming becomes the de facto standard - you might as well not bother with a throws clause in the first place. Why go to all the trouble of declaring throws in your library if your clients are not going to get any benefit from it? This is the argument that Walter clearly favours because there is no throws clause in the language. I agree with him in this respect - if you're not going to have strict exception specification, then you might as well not have any.
 I think libraries should document their errors with throws clauses,



 I wouldn't want the language to enforce that.

Can I ask a question of everybody on this thread? How many of you have actually spent anytime working with a language that has rigorous


 specification syntax (eg. Java)? I spent 18 months programming almost
 exclusively in Java and I honestly did not find having to declare


 a bother.

Java is a VM. There's a difference.

Ummmm. And why does that make a strict throws clause any easier for the programmer?
 As for API drift being a problem in this regard, it happens a hell
 of a lot less than you might imagine - and when it does happen, you can
 relax in the certain knowledge that you're compiler's going to tell you
 about each and every point at which changes in a 3rd party library has
 broken your code.

API drift may not happen much, but platform differences are another matter. That's one reason why errno can be ugly. With some many standard to choose from, which ones do you pick and how closely do you stick to each one. Vendors like to deviate from specs in order to accentuate their advantages in cases where specs try to pick least common denominators. Different implementation allow for different error conditions. With Java you have one platform, the JVM, and it is only liable to change every six months or however often Sun decides to mess with the world. When compiling to something less standard, say native operation systems, you have room for a lot more differences. This would have a bad gut feeling to anyone who has had to deal with portability a lot. You now have API drift for several different platforms, and they don't even happen at the same time.

And underneath the VM there is a whole host of different platforms each with their own error conditions which don't stop ocurring just because you've pasted a VM over the top of it all - and they all have to get reported one way or another. The fact is that most error conditions *aren't* platform specific - they may be reported in different ways, but an out of memory error is an still an out of memory error whether you're running Windows, Solaris, Irix, Linux, FreeBSD, BeOS, PalmOS, VMS, TRS-DOS or AppleSoft. Regards, John Carney.
Aug 29 2001
next sibling parent Dan Hursh <hursh infonet.isl.net> writes:
John Carney wrote:
 The problem is that lazy programming becomes the de facto standard - you
 might as well not bother with a throws clause in the first place. Why go to
 all the trouble of declaring throws in your library if your clients are not
 going to get any benefit from it? This is the argument that Walter clearly
 favours because there is no throws clause in the language. I agree with him
 in this respect - if you're not going to have strict exception
 specification, then you might as well not have any.

In that case, let me make Walter's case stronger for him. What good are strict exceptions clauses when everyone uses "throws(exception)"? You'll have that problem either way. At let's the quick tool's writer's will like you better if the lack of the clause gives them that behavior. For what it's worth, I would probably use them in most of my code because I'm anal. Where I work we tend to use them all the time in Java except for those things that are needed quick (as in yesterday) as a patch until we can get a real fix put together. In those cases everything throws "exception". I think it is a bit hasty to say no one would use the if given the choice. It sounds like you would. I would. I would berate any API designer who puts out a library for public without throws clauses (assuming we don't talk Walter out of them).
 Java is a VM.  There's a difference.

Ummmm. And why does that make a strict throws clause any easier for the programmer?

Vendors can make too many changes to the sun API. You are less of a victim of change. (At least that what sun tells us.) The sun API defines who can throw what. Period. It's not unreasonable to think that native code would be more subservient to a given platform's idiosyncrasies, including how things can fail. Every time any one of the vendors, who's platform you support, decides to make a change your code could be made uncompilable. The world gets a lot ruder. It's a legitimate concern that should be addressed. I tried to address that later on in the response.
 As for API drift being a problem in this regard, it happens a hell
 of a lot less than you might imagine - and when it does happen, you can
 relax in the certain knowledge that you're compiler's going to tell you
 about each and every point at which changes in a 3rd party library has
 broken your code.

API drift may not happen much, but platform differences are another matter. That's one reason why errno can be ugly. With some many standard to choose from, which ones do you pick and how closely do you stick to each one. Vendors like to deviate from specs in order to accentuate their advantages in cases where specs try to pick least common denominators. Different implementation allow for different error conditions. With Java you have one platform, the JVM, and it is only liable to change every six months or however often Sun decides to mess with the world. When compiling to something less standard, say native operation systems, you have room for a lot more differences. This would have a bad gut feeling to anyone who has had to deal with portability a lot. You now have API drift for several different platforms, and they don't even happen at the same time.

And underneath the VM there is a whole host of different platforms each with their own error conditions which don't stop ocurring just because you've pasted a VM over the top of it all - and they all have to get reported one way or another.

But Java got away with it because they provided the pretty picture that you would be insulted from all that. Java tries to make every thing look the same, and that is an easier task to do in a VM than on bare hardware. D is targeting bare hardware.
 The fact is that most error conditions *aren't* platform
 specific - they may be reported in different ways, but an out of memory
 error is an still an out of memory error whether you're running Windows,
 Solaris, Irix, Linux, FreeBSD, BeOS, PalmOS, VMS, TRS-DOS or AppleSoft.

Right, and so is a "File Not Found", or a "No More Processes" messages (those happen often in Windows, right?) or "Disk Quota Exceeded"? You are right, things can go wrong all over the place even in Java. It's just easier to anticipate the pain it will cause when you run native. At least it is for me. I've still convinced myself that exceptions must be a part of the API definition of a function. I've even convinced myself that you are less exposed to increased granularity of error reporting, but it did seem the opposite at first. In any case, I don't want to argue of whether there should be exception specifications, because we both think there should be. I would argue that since a developer can say he throws the exception base class, you might as well let him have it the easy way. If you don't it's not like there won't be editors that can be configured to do it for him. By allowing an open default, you will be helping the people need to do quick and dirty hacks every so often. Dan
Aug 29 2001
prev sibling parent reply "kaffiene" <kaffiene xtra.co.nz> writes:
 But this seems to defeat the lazy programer's purpose.  He's LAZY.  He
 doesn't want to have to declare that he's not declaring something.  That
 one of the things I find amusingly correct about perl's requirement that
 programmer who want to be forced to declare variables, have to declare
 that they want to have to declare variables.  The lazy programmer does
 nothing and gets the behavior that benefits lazy programmers.  It's
 poetic in nature.

<sigh> The problem is that lazy programming becomes the de facto standard - you might as well not bother with a throws clause in the first place. Why go

 all the trouble of declaring throws in your library if your clients are

 going to get any benefit from it? This is the argument that Walter clearly
 favours because there is no throws clause in the language. I agree with

 in this respect - if you're not going to have strict exception
 specification, then you might as well not have any.

...I agree. And if you're not going to have strict exception specification then you may as well not bother with design-by-contract either. Pre and post conditions exist to ensure that code is as safe and consistent as can be managed at compile time. There's no point painstakingly defining the contract for a method if an unforseen exception sidesteps it all. Peter.
Aug 30 2001
parent reply Dan Hursh <hursh infonet.isl.net> writes:
kaffiene wrote:
 
 But this seems to defeat the lazy programer's purpose.  He's LAZY.  He
 doesn't want to have to declare that he's not declaring something.  That
 one of the things I find amusingly correct about perl's requirement that
 programmer who want to be forced to declare variables, have to declare
 that they want to have to declare variables.  The lazy programmer does
 nothing and gets the behavior that benefits lazy programmers.  It's
 poetic in nature.

<sigh> The problem is that lazy programming becomes the de facto standard - you might as well not bother with a throws clause in the first place. Why go

 all the trouble of declaring throws in your library if your clients are

 going to get any benefit from it? This is the argument that Walter clearly
 favours because there is no throws clause in the language. I agree with

 in this respect - if you're not going to have strict exception
 specification, then you might as well not have any.

...I agree. And if you're not going to have strict exception specification then you may as well not bother with design-by-contract either. Pre and post conditions exist to ensure that code is as safe and consistent as can be managed at compile time. There's no point painstakingly defining the contract for a method if an unforseen exception sidesteps it all. Peter.

I think you are mistaking what I am saying. Exceptions are still enforced in my microcosm. The programmer simply does not need to give a throws clause. In that case, 'throws(exception)' or what ever the exception base class is can be assumed. Face it. If the programmer is lazy or in a rush, he will probably do this anyhow. You can't prevent it without actually making the compiler analyze the enter program to make sure the programmer's throws clauses are neither missing something nor are they too general. In that case you wouldn't need a throws clause because the compiler would figure it out itself. I don't believe that is practical. Maybe my original example should have been: larry() throws(); // I will throw nothing moe() throws(X, Y, Z); // I might throw X, Y & Z shemp(); // assume I could throw execption (aka anything) curly() throws(exception);// I can throw the same things as shemp Whether or not you make shemp illegal, you still has to deal with curly. nyuk nyuk nyuk Dan
Aug 30 2001
next sibling parent reply "kaffiene" <kaffiene xtra.co.nz> writes:
"Dan Hursh" <hursh infonet.isl.net> wrote in message
news:3B8F175C.F0F03CFF infonet.isl.net...
 kaffiene wrote:
 But this seems to defeat the lazy programer's purpose.  He's LAZY.




 doesn't want to have to declare that he's not declaring something.




 one of the things I find amusingly correct about perl's requirement




 programmer who want to be forced to declare variables, have to




 that they want to have to declare variables.  The lazy programmer




 nothing and gets the behavior that benefits lazy programmers.  It's
 poetic in nature.

<sigh> The problem is that lazy programming becomes the de facto standard -



 might as well not bother with a throws clause in the first place. Why



 to
 all the trouble of declaring throws in your library if your clients



 not
 going to get any benefit from it? This is the argument that Walter



 favours because there is no throws clause in the language. I agree



 him
 in this respect - if you're not going to have strict exception
 specification, then you might as well not have any.

...I agree. And if you're not going to have strict exception


 then you may as well not bother with design-by-contract either.  Pre and
 post conditions exist to ensure that code is as safe and consistent as


 be managed at compile time.  There's no point painstakingly defining the
 contract for a method if an unforseen  exception sidesteps it all.

 Peter.

I think you are mistaking what I am saying. Exceptions are still enforced in my microcosm. The programmer simply does not need to give a throws clause. In that case, 'throws(exception)' or what ever the exception base class is can be assumed. Face it. If the programmer is lazy or in a rush, he will probably do this anyhow. You can't prevent it without actually making the compiler analyze the enter program to make sure the programmer's throws clauses are neither missing something nor are they too general. In that case you wouldn't need a throws clause because the compiler would figure it out itself. I don't believe that is practical.

By disallowing strict exception specification you penalise carefull programmers to appease lazy programmers. That's simply a bad trade. Peter.
Aug 30 2001
parent reply Dan Hursh <hursh infonet.isl.net> writes:
kaffiene wrote:
 I think you are mistaking what I am saying.  Exceptions are still
 enforced in my microcosm.  The programmer simply does not need to give a
 throws clause.  In that case, 'throws(exception)' or what ever the
 exception base class is can be assumed.  Face it.  If the programmer is
 lazy or in a rush, he will probably do this anyhow.  You can't prevent
 it without actually making the compiler analyze the enter program to
 make sure the programmer's throws clauses are neither missing something
 nor are they too general.  In that case you wouldn't need a throws
 clause because the compiler would figure it out itself.  I don't believe
 that is practical.

By disallowing strict exception specification you penalise carefull programmers to appease lazy programmers. That's simply a bad trade.

Given the example I had: larry() throws(); // I will throw nothing moe() throws(X, Y, Z); // I might throw X, Y & Z shemp(); // assume I could throw exception (aka anything) curly() throws(exception);// I can throw the same things as shemp Tell me this. If we get rid of the shemp syntax, how would you deal with curly? Exceptions aside, any error reporting mechanism can be abused. Errno was grossly abused as were the various return code standards. That is a practical fact of life. Sometimes it's not even abuse. Sometimes you are writing a quick one shot tool that you need now. If there is an error you let the program bomb, you fix it on the spot and you continue. Where I work, it is called fire fighting. It is sub optimal, but we don't always have time to wait on a carefully analyzed master piece. The way I see it, you can't stop the curly example. It is a valid, strict specification. It is probably an over specification, but that is not something the compiler can reasonably detect I would assume. Anything that would detect that, I suspect, would make other over specifications illegal when they may be valid for future planning. If you can't argue on HOW to prevent the curly form of abuse, then I don't see the problem with making it explicit with the shemp syntax. Since shemp would be a synonym for curly, it is no less strict that curly. Honestly, I think it makes the lack of a careful promise more obvious. I certainly don't agree with the argument that "It's bad style so we should penalize it with the syntax". If that is our plan then let's replace goto with some that takes a few lines and lots of redundancy. Goto has been the root of far more evil than under specifying error conditions. Dan
Aug 30 2001
parent "kaffiene" <kaffiene xtra.co.nz> writes:
"Dan Hursh" <hursh infonet.isl.net> wrote in message
news:3B8F2EC1.32A08053 infonet.isl.net...
 kaffiene wrote:
 I think you are mistaking what I am saying.  Exceptions are still
 enforced in my microcosm.  The programmer simply does not need to give



 throws clause.  In that case, 'throws(exception)' or what ever the
 exception base class is can be assumed.  Face it.  If the programmer



 lazy or in a rush, he will probably do this anyhow.  You can't prevent
 it without actually making the compiler analyze the enter program to
 make sure the programmer's throws clauses are neither missing



 nor are they too general.  In that case you wouldn't need a throws
 clause because the compiler would figure it out itself.  I don't



 that is practical.

By disallowing strict exception specification you penalise carefull programmers to appease lazy programmers. That's simply a bad trade.

Given the example I had: larry() throws(); // I will throw nothing moe() throws(X, Y, Z); // I might throw X, Y & Z shemp(); // assume I could throw exception (aka anything) curly() throws(exception);// I can throw the same things as shemp Tell me this. If we get rid of the shemp syntax, how would you deal with curly? Exceptions aside, any error reporting mechanism can be abused. Errno was grossly abused as were the various return code standards. That is a practical fact of life. Sometimes it's not even abuse. Sometimes you are writing a quick one shot tool that you need now. If there is an error you let the program bomb, you fix it on the spot and you continue. Where I work, it is called fire fighting. It is sub optimal, but we don't always have time to wait on a carefully analyzed master piece. The way I see it, you can't stop the curly example. It is a valid, strict specification. It is probably an over specification, but that is not something the compiler can reasonably detect I would assume. Anything that would detect that, I suspect, would make other over specifications illegal when they may be valid for future planning. If you can't argue on HOW to prevent the curly form of abuse, then I don't see the problem with making it explicit with the shemp syntax. Since shemp would be a synonym for curly, it is no less strict that curly. Honestly, I think it makes the lack of a careful promise more obvious. I certainly don't agree with the argument that "It's bad style so we should penalize it with the syntax". If that is our plan then let's replace goto with some that takes a few lines and lots of redundancy. Goto has been the root of far more evil than under specifying error conditions.

Your argument appears to be that because some people can partly side-step a language feature it shouldn't be there at all. I don't agree. I certainly don't agree that a language feature designed to produce correct code should be rejected to favour quick hacks. I think that a lot of the point of coding in a higher level language than C is that you are aiming to produce cleaner, more reliable code than you could in C. Besides, I don't see the difference between having to declare unhandled exceptions and not being able to have unused variables. If you have an unused variable, the D compiler will complain and you will duck into the code, delete the variable or comment it out (or fix the bug if it was one) then recompile. That doesn't seem too difficult a task even for someone in a hurry. If you have strict exception specfication the compiler might complain that your new method isn't handling an exception and should either catch it or declare it with a throws clause. You duck into the code and handle it or pass it on - no big deal. I also think this 'shem vs curly' issue you raise is something of a straw-man argument. If someone wants to go out of their way to abuse exception specification because they're hacking, then fine - that's their perogative. They are free to do that with expection specification. However, people who want to code clean, reliable, reusable code need to know that their modules are as good as they can get. If you allow: method() // I can throw anything to mean an method which can throw any exception, then you remove an incredibly useful tool from the careful programmer's tool chest, because the compiler can now no longer tell whether the code you are writing is wrong because you haven't handled an exception or whether you really meant it to be like that and you wanted all the exceptions to percolate through your code right out to main and bomb the program. You have two options: strict exception specification and no exception specification at all (a halfway measure helps noone as pointed out above). If you go for no exception specifications, then hackers are happy and people who want correct code get no help at all (may as well not bother with design-by-contract either if that's your point of view). If you go for strict exception specification, hackers can still hack - using throws(exception) to their heart's desire, but people aiming to write and mantain correct code are not penalised, and can get a great deal of support by the compiler to do so. I have had experience with maintaining large code bases in C++ and Java (plus having to do quick hacks - for support reasons - in both languages). I know from experience that strict exception specification is a major win. (I don't mean to presume to know anything about your programming experience, BTW) I cannot stress strongly enough how much I think ignoring strict exception specification is a *bad idea*. C++ takes the weak exception specfication route because of legacy reasons, and Barney Soupstrain rates it as one of the biggest regrets he has about C++. He's right! ;-) Peter.
Aug 31 2001
prev sibling parent Russ Lewis <russ deming-os.org> writes:
Dan Hursh wrote:

 I think you are mistaking what I am saying.  Exceptions are still
 enforced in my microcosm.  The programmer simply does not need to give a
 throws clause.  In that case, 'throws(exception)' or what ever the
 exception base class is can be assumed.  Face it.  If the programmer is
 lazy or in a rush, he will probably do this anyhow.  You can't prevent
 it without actually making the compiler analyze the enter program to
 make sure the programmer's throws clauses are neither missing something
 nor are they too general.

The compiler can analyze each function individually. If you throw an exception in a function (or call a function that throws an exception that you don't catch) but you don't declare it, it's a syntax error. Then, when you call any function, you can guarantee that that function will be bound to only throwing the exception it declares. Am I missing something?
 In that case you wouldn't need a throws
 clause because the compiler would figure it out itself.  I don't believe
 that is practical.

 Maybe my original example should have been:

 larry() throws();         // I will throw nothing
 moe() throws(X, Y, Z);    // I might throw X, Y & Z
 shemp();                  // assume I could throw execption (aka anything)
 curly() throws(exception);// I can throw the same things as shemp

If D implements strict exception specification, then the shemp() declaration should mean an explicit declaration that it throws *nothing*.
Aug 31 2001
prev sibling parent "kaffiene" <kaffiene xtra.co.nz> writes:
 Can I ask a question of everybody on this thread? How many of you have
 actually spent anytime working with a language that has rigorous exception
 specification syntax (eg. Java)? I spent 18 months programming almost
 exclusively in Java and I honestly did not find having to declare

 a bother. As for API drift being a problem in this regard, it happens a

 of a lot less than you might imagine - and when it does happen, you can
 relax in the certain knowledge that you're compiler's going to tell you
 about each and every point at which changes in a 3rd party library has
 broken your code.

I've been programming Java/C++/C interchangibly over the past three years. I've never found exception specification to be a bother in Java, rather I've found it to be a great help. I've never shipped code wondering whether some unforeseen exception might scuttle it, and quite often I've seen the compiler complain about some unhandled exception and been pleased that it did. Peter.
Aug 30 2001
prev sibling parent Jim Farrand <farrand cs.bris.ac.uk> writes:
Walter wrote:
 
 Here's my problem with a throws clause:
 
 A calls B
 B calls C
 C calls D
 
 D is in some third party library. Now, D is updated to throw another
 exception. Now, the code in C, B, and A all needs to be updated. 

But C, B and A *should* be updated. If D now throws another type of exception, there is now something new that can go wrong with D. C, B and A need to take account of this - otherwise, what happens when D does throw this new exception? IMHO the exceptions thrown by a function are part of it's interface. Other interface changes in D would result in changes in code which calls D. Why not the same with exceptions? -- Jim Farrand, ML Group, mailto:farrand cs.bris.ac.uk Department of Computer Science, http://www.cs.bris.ac.uk/~farrand University of Bristol, tel: +44-(0)117-954-5254 Woodland Road, Bristol, BS8 1UB, UK
Aug 29 2001