August 28, 2001
> 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

August 28, 2001
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
August 28, 2001
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
August 28, 2001
> 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

August 28, 2001
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
August 28, 2001
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>.


August 28, 2001
<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.


August 29, 2001
> 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? :)

August 29, 2001
> 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

August 29, 2001
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