Java and single inheritance

Started by
251 comments, last by zacharya 20 years, 1 month ago
quote:Or you could have forgotten about it. If I was maintaining your code, how am I suppose to know that you deliberately didn''t handle it or you just forgot to?

How am I meant to know if you really can (or should) handle an exception in a piece of code, or are just catching it to make the compiler shut up? I may see you catching an exception, but I''ve still got to take it on trust that in so doing you''re not compromising the integrity of the system.

quote:How can you be confident that you didn''t forget about an exception that is now going to crash your program when it is thrown? I''d love to see your source code where you apparently can''t handle any exceptions ever.

I''d be curious to see *your* code to see why you''re getting lots of exceptions that you *can* handle.

How can I "handle", for example, an SQLException or a RemoteException? There''s just no way of finding out what went wrong (hell, at least one of the JDBC drivers I use regularly doesn''t even always bother populating the SQLException to provide any vendor-specific information), and *certainly* no way of fixing it. A top-level catch(Exception e) { e.printStackTrace(); } is as good as can be done.
char a[99999],*p=a;int main(int c,char**V){char*v=c>0?1[V]:(char*)V;if(c>=0)for(;*v&&93!=*v;){62==*v&&++p||60==*v&&--p||43==*v&&++*p||45==*v&&--*p||44==*v&&(*p=getchar())||46==*v&&putchar(*p)||91==*v&&(*p&&main(0,(char**)(--v+2))||(v=(char*)main(-1,(char**)++v)-1));++v;}else for(c=1;c;c+=(91==*v)-(93==*v),++v);return(int)v;}  /*** drpizza@battleaxe.net ***/
Advertisement
quote:The compiler cannot verify this will not throw an exception so you''ve got to help it out here.

Sure it can. It can see the static types being used. It knows damn well that the exception can''t be thrown. But it has to pretend that it can be anyway.

quote:Why can''t you catch it and not do anything, then add a comment that it can never be thrown under these conditions?

Why should I have to?!

quote:If you really want, make a utility method so you''ve only got to do this once. I wouldn''t put IOException in the exception specifier, you just said it shouldn''t fail.

The problem is that the Java designers *did* put it in their exception specification. And in so doing, they''ve made the interface over-specified.

quote:I really just don''t understand why you have so much trouble with this. I use Java daily and these kind of issues are so rare the advantages are worth the annoyances. Like, say, MI.

There is no advantage to forcing people to deal with exceptions that they can''t actually deal with. It just promotes writing less robust, less correct programs.

You''re keen on omitting features in case people misuse them. I put it to you that checked exceptions should be classed as such a feature. The principle reason is the naive -- but extremely common response to checked exceptions:
catch(Exception e) {} 

because the developer in question just wanted their damn code to compile. They may intend to go back to the code and do something more appropriate, they may not. Either way, they''ve just written something extremely dangerous and completely lacking in robustness. The rest of their program will, because of that clause, think that everything''s fine with the function. It''s particularly misleading because even unchecked exceptions will be caught by that clause. Oh, sure, if the exceptions weren''t caught the stack would unwind and the program would crash. But I would suggest that that is more robust than this kind of improper handling. A program that''s crashed can''t go on to break anything. The stack unwinding will ensure that anything''s tidied up as necessary -- database transactions will be rolled back, that kind of thing.

And what annoyances (that aren''t fictional) does MI cause?
char a[99999],*p=a;int main(int c,char**V){char*v=c>0?1[V]:(char*)V;if(c>=0)for(;*v&&93!=*v;){62==*v&&++p||60==*v&&--p||43==*v&&++*p||45==*v&&--*p||44==*v&&(*p=getchar())||46==*v&&putchar(*p)||91==*v&&(*p&&main(0,(char**)(--v+2))||(v=(char*)main(-1,(char**)++v)-1));++v;}else for(c=1;c;c+=(91==*v)-(93==*v),++v);return(int)v;}  /*** drpizza@battleaxe.net ***/
quote:Original post by DrPizza
How am I meant to know if you really can (or should) handle an exception in a piece of code, or are just catching it to make the compiler shut up? I may see you catching an exception, but I''ve still got to take it on trust that in so doing you''re not compromising the integrity of the system.


You''re right, the Java code you posted did seem quite stupid. I didn''t read up on the interfaces, but it would have been nice if they could have worked out a way for guarenteed things not to throw. I''ve sure if you read the interfaces it is either said or implied that code should never ever fail, so it seems safe to ignore that exception.

quote:
I''d be curious to see *your* code to see why you''re getting lots of exceptions that you *can* handle.

How can I "handle", for example, an SQLException or a RemoteException? There''s just no way of finding out what went wrong (hell, at least one of the JDBC drivers I use regularly doesn''t even always bother populating the SQLException to provide any vendor-specific information), and *certainly* no way of fixing it. A top-level catch(Exception e) { e.printStackTrace(); } is as good as can be done.


Well you obviously cannot handle these then. Not everybody is writing the same applications as you remember. It could be a GUI which uses a database, so you''d want the user to know the database isn''t working or something sensible in that context. If it is a server side program, logging is obviously going to be useful because it can help you track down problems. If this is an exceptable way of handling things here, that''s fine. I just find exception specifications useful for what I do.
quote:That really depends on the context and i have to point you that your example didnt have one

I know it didn''t. But that''s kind of the point. Interfaces are written without any context. As such they must be appropriate whatever the situation they''re being used in. For a small console program (the kind of thing where the entire program fits on-screen) then perhaps an interface with checked exceptions makes sense. But that doesn''t mean it makes sense in a LOB system that''s running on a dozen headless servers 24/7.

With unchecked exceptions, it doesn''t matter -- I can catch the exceptions when it makes sense to, I can ignore them when it doesn''t. As such the interface is correct whatever the context. But checked exceptions force me to handle the exceptions even when it''s *not* appropriate.

quote:i really wonder where that tremendous statement comes from?

Wide experience.

quote:i rather have the opposite idea but hey! i check for errors instead of crash my application!

I''m quite happy for the application to crash if something''s happened that shouldn''t have.

quote:uh?
what''s the point? are you implying that this is a rather common situation? or you''re trying to tell me that since few times you have that you got crazy?

I''m telling you that the interface is over-specified, because it forces me to "handle" errors that cannot possibly occur.

quote:your attitude amazes me...

Because I don''t spend my time programming trying to second-guess the system and recover from errors? What''s amazing about that? It''s pragmatism, and it makes for more robust, less buggy code.

quote:ok so you just asume that there''s no file saving, no database transaction, nothing at all, right...

Where did you get that idea? I just said these things are taken care of by the stack unwind.

quote:another one... how comes that it violates encapsulation and since when you''re an oop purist?
exception gives you the information about possible unexpected events that you may have to deal with, it doesnt reveal how they are performed. that''s nonsenses

You don''t get it, do you?

If the situation is expected, I''m happy to handle the exception. If the situation is unexpected I probably can''t.

And, yes, it does reveal how they''re performed. If I need to throw, say, an SQLException that says quite a lot about my implementation.

quote:Boyyyyyyy i don''t get your attitude, sorry that i cant help you to understand why the bigger players in the market took the decisions they did (i''m sure it wasnt because they want to make you unhappy, believe me...)

Exactly one player has taken that decision, and no-one has followed in their footsteps. Even the Java community itself isn''t particularly enthused by checked exceptions -- they''ve shown themselves empirically to reduce developer productivity but offer no practical benefits to offset this.
char a[99999],*p=a;int main(int c,char**V){char*v=c>0?1[V]:(char*)V;if(c>=0)for(;*v&&93!=*v;){62==*v&&++p||60==*v&&--p||43==*v&&++*p||45==*v&&--*p||44==*v&&(*p=getchar())||46==*v&&putchar(*p)||91==*v&&(*p&&main(0,(char**)(--v+2))||(v=(char*)main(-1,(char**)++v)-1));++v;}else for(c=1;c;c+=(91==*v)-(93==*v),++v);return(int)v;}  /*** drpizza@battleaxe.net ***/
quote:Original post by DrPizza
Sure it can. It can see the static types being used. It knows damn well that the exception can''t be thrown. But it has to pretend that it can be anyway.


Ok, maybe they should add in some checking for this then. It doesn''t happen often enough for me to notice though.

quote:
quote:Why can''t you catch it and not do anything, then add a comment that it can never be thrown under these conditions?

Why should I have to?!


Because it documents your intent and shows in code that you want to ignore the exception. Programmers make mistakes and assuming they''re always doing the right thing first is going to lead to errors.

quote:
The problem is that the Java designers *did* put it in their exception specification. And in so doing, they''ve made the interface over-specified.


That''s a problem with their interface design then, not checked exceptions.

quote:
You''re keen on omitting features in case people misuse them. I put it to you that checked exceptions should be classed as such a feature. The principle reason is the naive -- but extremely common response to checked exceptions:
catch(Exception e) {}  

because the developer in question just wanted their damn code to compile. They may intend to go back to the code and do something more appropriate, they may not. Either way, they''ve just written something extremely dangerous and completely lacking in robustness. The rest of their program will, because of that clause, think that everything''s fine with the function. It''s particularly misleading because even unchecked exceptions will be caught by that clause. Oh, sure, if the exceptions weren''t caught the stack would unwind and the program would crash. But I would suggest that that is more robust than this kind of improper handling. A program that''s crashed can''t go on to break anything. The stack unwinding will ensure that anything''s tidied up as necessary -- database transactions will be rolled back, that kind of thing.


Your argument hindges on programmers ignoring exceptions because they cannot be bothered dealing with them properly. If they aren''t going to deal with them properly, they weren''t going to anyway.

If I''m working with bad coders they will write bad code no matter how much the language mollycoddles them. So that argument doesn''t fly. Oh, wait, you said that.

quote:
And what annoyances (that aren''t fictional) does MI cause?


I''m not going over this again. I provided at least two links, other people in this thread have said it caused problems and there are programming languages that do not have MI because of the known complications they introduce. If you are not going to accept the annoyances of MI from them, you are certainly not going to accept them from me.
quote:You''re right, the Java code you posted did seem quite stupid. I didn''t read up on the interfaces, but it would have been nice if they could have worked out a way for guarenteed things not to throw. I''ve sure if you read the interfaces it is either said or implied that code should never ever fail, so it seems safe to ignore that exception.

But I can''t ignore it. It''s a checked exception. I''ve *got* to deal with it (or make my caller deal with it, which amounts to the same thing).

quote:Well you obviously cannot handle these then. Not everybody is writing the same applications as you remember.

No, they''re not. I know. This just reinforces my position.

If an exception is unchecked, there''s nothing to stop you from catching it if you want to. If you think you can report an SQLException in a useful way, more power to you -- go right ahead and handle it. If you want to produce a little message box for your user (because you have a user and message boxes and all that stuff) then produce a little message box for your user. That''s fine, it works perfectly well with unchecked exceptions.

The problem is that I''ve got to use the same interfaces in a scenario where I *can''t* just produce a little message box for the user. I don''t have a user. I don''t have message boxes. What I *want* to do when an exception is thrown is to let it unwind the stack all the way -- thereby cleaning my application up -- where I can then spit out a stack trace to a log file, and crash the application so that it can restart (or perhaps something more complicated, but that''s the main thrust of it). I want to do that because I can''t afford to run in an inconsistent state; I can''t run without, for example, database access or remote interfaces working. There''s no way I can limp along. And checked exceptions *stop* me from doing this conveniently.

Checked exceptions may work well in small applications; they don''t scale to large ones.

quote:It could be a GUI which uses a database, so you''d want the user to know the database isn''t working or something sensible in that context. If it is a server side program, logging is obviously going to be useful because it can help you track down problems. If this is an exceptable way of handling things here, that''s fine. I just find exception specifications useful for what I do.

We''re talking about something much stronger than exception specifications. C++ has exception specifications. Exception specifications provide convenient documentation and optimization benefits; I''ve no real gripe with exception specifications (C++''s unexpected exception business isn''t good, mind you, but that''s a topic for another thread). It''s checked exceptions -- forcing me to deal with things whether I want to or not, whether I''m able to or not, whether it''s appropriate or not, without any care for the context -- that are the problem.
char a[99999],*p=a;int main(int c,char**V){char*v=c>0?1[V]:(char*)V;if(c>=0)for(;*v&&93!=*v;){62==*v&&++p||60==*v&&--p||43==*v&&++*p||45==*v&&--*p||44==*v&&(*p=getchar())||46==*v&&putchar(*p)||91==*v&&(*p&&main(0,(char**)(--v+2))||(v=(char*)main(-1,(char**)++v)-1));++v;}else for(c=1;c;c+=(91==*v)-(93==*v),++v);return(int)v;}  /*** drpizza@battleaxe.net ***/
quote:Ok, maybe they should add in some checking for this then. It doesn''t happen often enough for me to notice though.

Lucky you.

quote:Because it documents your intent and shows in code that you want to ignore the exception.

The code expresses my intent already.

quote:That''s a problem with their interface design then, not checked exceptions.

No, you can''t say that. Unhandled checked exceptions must be added to signatures, and those exception specifications form a part of the signature, and hence interface.

quote:Your argument hindges on programmers ignoring exceptions because they cannot be bothered dealing with them properly. If they aren''t going to deal with them properly, they weren''t going to anyway.

If I''m working with bad coders they will write bad code no matter how much the language mollycoddles them. So that argument doesn''t fly. Oh, wait, you said that.

You''re the one advocating changing language design to account for bad programmers. Or is this situation different just because you happen to like checked exceptions?

Checked exceptions provide no benefits for good programmers, and just produce problems with bad programmers. This makes them unlike MI, which provide benefits for good programmers, and theoretically produce problems for bad programmers (though in practice bad programmers don''t use MI anyway).

quote:I''m not going over this again. I provided at least two links, other people in this thread have said it caused problems and there are programming languages that do not have MI because of the known complications they introduce. If you are not going to accept the annoyances of MI from them, you are certainly not going to accept them from me.

Yeah, you provided a link or two. The reasons given in those links were specious. The "problems" of MI are smaller than the problems one experiences when attempting to use SI in similar situations. Does having repeated base classes cause issuse that one should be aware of? Sure. But they''re not difficult issues, and are, for the most part, caught staticly by the compiler. It''s just not that big a problem. Certainly not enough to justify complete omission of the feature.
char a[99999],*p=a;int main(int c,char**V){char*v=c>0?1[V]:(char*)V;if(c>=0)for(;*v&&93!=*v;){62==*v&&++p||60==*v&&--p||43==*v&&++*p||45==*v&&--*p||44==*v&&(*p=getchar())||46==*v&&putchar(*p)||91==*v&&(*p&&main(0,(char**)(--v+2))||(v=(char*)main(-1,(char**)++v)-1));++v;}else for(c=1;c;c+=(91==*v)-(93==*v),++v);return(int)v;}  /*** drpizza@battleaxe.net ***/
quote:Original post by seanw
quote:Original post by sjelkjd
My point is that checked exceptions don''t help you at all here, they just require you to pollute your tree walking code with exception specifications that don''t get handled or generated in the tree code. This broad specification goes on to infect the rest of your code. Now any method that calls this tree walker has to throw exception or catch exception.


I don''t understand this use of the word pollution. Any method that calls the tree walker now has to handle a possible error or say that it isn''t so the caller now knows what it has to handle it. This seems like good error handling to me.

But this is idiotic - your callback may only generate exceptions X and Y, but because you wanted your tree walker to be used by anyone, it specifies that it throws java.lang.exception(or whatever the base exception is). Now, whatever code uses your tree walker has to handle all possible exceptions, even though only a small subset of those can actually be thrown! And how is the caller supposed to deal with any exception, when it only cares about the actual exceptions that its callback throws?

quote:
I''ve suggested putting the specific callback exception inside a general exception object that the callbacks can throw, so then you can get this information if you really want it. You could also just let the callbacks throw anything they want. I prefer strong interfaces though with a suitable level of abstraction to what they are being used for.

Or you could get rid of checked exceptions and not have to use either of these hacks. Also note that in the first case, callers have to specifically wrap their exceptions in some *other* exception object, which is probably incompatible with any exception handling going on elsewhere in your program. Or do you suggest recoding all other exception handling to understand a TreeWalkerException, and how to unpack it to get to the real exception?

quote:
How would you indicate the error otherwise without using exceptions? You could use return codes, but then you''re going to ''pollute'' your tree walker code by playing around with them also.

You throw and catch exceptions as usual. The only difference is that in one case, every method has a throws Exception tagged to it, and in the other case, it doesn''t have anything tagged to it.

Neither of these two cases actually indicate anything useful about what exceptions are thrown, but the checked exception case wastes the developer''s time by making him deal with useless exception specifications.
If you hate checked exceptions you could :

a) stop using Java
b) wrap your exceptions in RuntimeException (non checked) and resend them

Using b) you''ll get a nice, fail fast, keyboard friendly way of NOT handling exception.
quote:Original post by overnhet
The usual way to deal with this is to provide a FooProviderException which encapsulates the "real" exception and has a getException() method, so that you have only one exception type to catch AND you don''t lose information.

Well, sure. But, as I said, that doesn''t guarantee that the exception is checked safely.
quote:
Anyway if you use an interface to abstract the Foo providing logic, the caller obviously can''t understand what you are doing in FooProvider.get() so you shouldn''t expect it to handle a failure at low-level.

But the caller of the caller might .
void doFooWithDB (Database db){  while (true) {    try {      Database db = new Database;      FooConsumer fc = new FooConsumer(new FooProvider());      fc.consume();      break;    } catch (DBConnectionDropped e) {      db.reconnect();    }  }} 

We cannot check that the DBConnectionDropped exception is being handled.
quote:
The caller should react to the fact that he can''t get its Foo object and not care about possible resource leak (for example).

You have to be joking? I should write a program that doesn''t care about resource leaks?
quote:
It could either show a warning window, log the error, try again or crash badly, depending how "vital" is Foo.

Obviously, without knowing what the error is, it''s difficult to know what to do. The program could have enough information to solve the problem by itself -- e.g. the connection dropped situation.

To decide that the problem will not be resolved, or you''ll just try again (which will obviously not work if you don''t try to reconnect) is hardly a solution.

To do so because handling the exceptions the Right Way is against the philosophy of the language is just stupid.
CoV

This topic is closed to new replies.

Advertisement