Why does Java require the throws clause? Good or bad language design?

C

Chris Smith

Robbert Haarman said:
All I meant is that it can be deduced from throw statements,
and that the throws clause is, thus, redundant.

I'd revise that a little. A guess at the throws clause can be deduced
from throw statements. In the specific case of private or final
methods, or methods in final classes, something very close to the throws
clause can de deduced (such that differences require future code changes
to manifest themselves). In general, though, the throws clause is an
implementation decision and therefore cannot be reliably deduced.

Of course, that's true of all type inference. When I write in Haskell:
firstLetter (c:cs) = c, I clearly meant for this to be of type String
(aka, [Char]), but all Haskell will infer is [a]. The difference is
that in that case, the inferred type is at least as permissive as the
actual type. When inferring a throws clause of any use at all, the
inferred throws clause will be at MOST as permissive. For this reason,
it becomes a bigger deal that it might be wrong.
 
L

Lew

Robbert said:
Of course, I wasn't claiming that the information comes from nowhere. Of
course, it comes from something some programmer entered. All I meant is
that it can be deduced from throw statements, and that the throws clause
is, thus, redundant.

No, it can't, because not every implementation of a method will necessarily
throw every checked exception for that method. The only way for Java to know
what checked exceptions might (not will) be thrown is through the throws
clause, and the throws clause is, thus, not redundant.

There is no general way for Javadocs to infer what may be thrown save by at
least the throws clause, and in practice, by the @throws tag. Thus the idea
that Javadocs might figure into the "automagic" throws mechanism is not, at
present, real.

There is no general way, in the face of interfaces, abstract classes, and
method overrides in extrinsic subclasses linked at runtime, to magically
deduce at compile time what checked Exceptions might be thrown. That isn't
what checked exceptions are for in the first place. They exist for an API
designer to specify what checked Exceptions are allowed to be thrown, and
therefore must be checked. The throws clause does not guarantee which ones of
those will be thrown. So you cannot analyze from what is thrown at runtime
what the API designer intended should be allowed. Ergo, the throws clause
exists to give the API designer that power.

This must be a manual entry by the programmer, up until we get computers that
do what we want instead of what we tell them.

- Lew
 
L

Lew

James said:
How about simply allowing the catching to be done higher up?

Not feasible at compile time, because information about what invocations may
exist "higher up" is not reliably available at compile time.

The throws clause would not be needed if the type resolution were done
strictly at run time, but it happens at compile time. The throws clause is
written by the API designer, who cannot know what clients will exist in the
future. It is enforced by the compiler on the API caller, because it cannot
know who will call the caller, and therefore cannot be sure there will be
handling "higher up". At compile time.

- Lew
 
C

Chris Smith

I think we're largely in agreement, but I'll nitpick anyway. Hope you
don't mind! :)

Lew said:
The throws clause would not be needed if the type resolution were done
strictly at run time, but it happens at compile time.

Clearly the throws statement is not needed in any case. The point that
it can be inferred is a valid one. The further point that it can be
inferred incorrectly is also important; but as a default, most (I'd
guess 99%) methods want to declare only the exceptions that they
actually throw. I might call it reasonable that the default is to infer
the clause and let it be explicitly specified if desired. I might also
want a warning, though, whenever a public or protected method in a
public class fails to explicitly specify a throws clause.

(Of course, this is changing the language, and there would need to be
other changes as well; for example, there'd need to be a way to
distinguish between "throws nothing" and "infer the throws". But as
long as we're changing the language, we ought to be able to handle
syntax, right?)
 
L

Lew

Chris said:
I think we're largely in agreement, but I'll nitpick anyway. Hope you
don't mind! :)

I don't mind at all.

Clearly the throws statement is not needed in any case. The point that
it can be inferred is a valid one. The further point that it can be
inferred incorrectly is also important; but as a default, most (I'd
guess 99%) methods want to declare only the exceptions that they
actually throw.

Meaningless statistic, and begs the question of what the throws clause is for.
The throws clause allows programs that use, say, interfaces and abstract
classes to invoke behavior to know what possible exceptions must be checked.
There is no way for such a class to know at compile time which runtime method
might actually be invoked, and it can vary from run to run of the same
program. The throws clause does not exist to support cases where the inference
can be made, it exists to lock down a guarantee that allows the compiler to
perform validation of a method's contract. Thus I can compile a JAR with
complete assurance of the contract, enforced at compile time, that all client
classes outside the JAR will know what exceptions to catch.

The throws clause is a design artifact, something the API programmer uses to
force compliance to a contract, and whether there is at contract definition
time even an implementation, let alone some arbitrary percentage that uses all
the declared exceptions, is irrelevant. What is relevant is that all future
implementations will adhere to the same contract, so that client software will
not have to reinfer the throws clause just because I changed an implementation
detail in revision 2.

I might call it reasonable that the default is to infer
the clause and let it be explicitly specified if desired. I might also
want a warning, though, whenever a public or protected method in a
public class fails to explicitly specify a throws clause.

There is absolutely nothing wrong with failing to specify a throws clause in
Java. That is part of the design of the method. The programmer's job is to
design the method to fulfill the contract, so don't throw any checked
exceptions that the contract does not specify, but throw all the unchecked
exceptions that you like, or none, as you like.

The throws clause is OPTIONAL. People are arguing about it like it is some
sort of stricture - you DO NOT NEED TO DECLARE A THROWS CLAUSE IN ANY METHOD
if you do not want to force calling code to deal with such an exception. If
you have an issue with a method someone else wrote that used the throws
clause, your beef is with the API designer, not the language.

- Lew
 
C

Chris Smith

Lew said:
Meaningless statistic

Absolutely. I hope it was clear that I didn't actually measure that
number. You could easily convince me that the real number is closer to
95%, for example. I feel safe in relying on my experience enought to
say "most," though.

It would be interesting to measure the number for some non-trivial piece
of code; but I lack the motivation to write the analysis tool at the
moment.
The throws clause allows programs that use, say, interfaces and abstract
classes to invoke behavior to know what possible exceptions must be checked.

Yep. It's definitely not feasible to try to infer the optimal throws
clause of any (non-final, non-private) method. This would need to be
handled by inferring something that's incomplete, and then simply
requiring that other exceptions be listed if they need to be throwable.

The inference will still be correct almost all of the time.
The throws clause is OPTIONAL.

Not in any meaningful sense of the word. It is impossible to write non-
trivial code of reasonable quality in Java without using the throws
clause.
 
J

John W. Kennedy

Lew said:
You certainly are entitled to your opinion.

I prefer to take the approach that "Java's approach is what it is",
without "wrong" or "right". Is it a perfect computer language? Is there
any such thing?

Java requires that checked exceptions be declared in a method's
declaration. It does not require that any method you write should
declare a checked exception. It is a language feature that you are free
not to use.

I agree with you that there are inconveniences to the exception idiom.
Calling such things "wrong" without regard for their purpose is cute but
not very useful. Even if they are "wrong", they exist in Java as they
exist in Java.

The only "wrong" thing in Java is that which violates its own
definition, i.e., the JLS. The evaluations we can make as programmers are;

- "I like / dislike that feature", to which I would reply, "Great!"
- "This feature could be expressed in a different language with greater
convenience to the programmer", to which I reply, "You make a very good
case."
- "This feature is / is not worth the effort in the particular situation
...", to which I reply, "That is a very sensible engineering decision."

But "wrong" or "right"? Not engineering evaluations.

I'm not sure that's always true. I think the decision in COBOL 60 to
make the question of intermediate-result precision
implementation-dependent was wrong, period. The same with the decision
in ALGOL 60 not to define a usable syntax for machine use, or any kind
of I/O system.

But such cases are rare. Even things that I regard as massively wrong in
hindsight (the COBOL PERFORM statement, anonymous pointers and the
conflation of boolean and short-circuit operators in PL/I, naming two of
the most central functions in LISP after their 7090 hardware
implementations, designing C string functions on the assumption of a
one-character buswidth,...) usually seemed reasonable at the time.

I can't really think of anything badly wrong with Java, even in hindsight.
 
L

Lew

Chris said:
Not in any meaningful sense of the word. It is impossible to write non-
trivial code of reasonable quality in Java without using the throws
clause.

Because it is so useful. You are supporting my point. But from a syntactic and
semantic point of view, it is optional. When you write the method, you decide
whether to include a throws clause. If you do, it is because the clause was
useful. If you cannot write a non-trivial program without using the throws
clause, and I agree with that by and large, it is because the throws clause
solves non-trivial problems.

If you are saying you cannot write a non-trivial program without handling
checked exceptions that someone else wrote, again I agree with you by and
large, but that is because the throws clause is doing exactly what it is
supposed to do. Those API writers were told that the throws clause would force
you to deal with certain exceptions. Now you are forced to deal with those
exceptions. It did what it was supposed to do.

People, the throws clause exists to force you to deal with the checked
exceptions. Your complaint is that you are forced to deal with the exceptions
declared in the throws clause. That just means the throws clause did its job.
It is there to force you to deal with those exceptions. How else would an API
designer force you to deal with those exceptions?

If you do not like it, do not blame the language for giving those API
designers too much power. After all, it is a power you yourself may choose to
wield on the users of your own code (yourself included).

- Lew
 
R

Robbert Haarman

No, it can't, because not every implementation of a method will necessarily
throw every checked exception for that method. The only way for Java to
know what checked exceptions might (not will) be thrown is through the
throws clause, and the throws clause is, thus, not redundant.

Ok, yes. If your goal is to allow programmers to specify which
exceptions a client must be prepared to handle, regardless of whether
these exceptions can occur in practice, the throws clause is not
redundant.

If your goal is to enumerate precisely which exceptions can be thrown by
some code, you would have to look at throw statements, and the throws
clause would be redundant (and, in Java's case, could make the compiler
force clients to write code to handle exceptions that cannot occur).
There is no general way, in the face of interfaces, abstract classes, and
method overrides in extrinsic subclasses linked at runtime, to magically
deduce at compile time what checked Exceptions might be thrown. That isn't
what checked exceptions are for in the first place. They exist for an API
designer to specify what checked Exceptions are allowed to be thrown, and
therefore must be checked. The throws clause does not guarantee which ones
of those will be thrown. So you cannot analyze from what is thrown at
runtime what the API designer intended should be allowed. Ergo, the throws
clause exists to give the API designer that power.

Exactly. I understand, now. And if the ability to specify exceptions
that clients must be prepared to deal with, regardless of whether these
exceptions can be thrown, is a desirable feature, then the throws clause
(or, of course, another mechanism) is necessary, and thus also
desirable.

Regards,

Bob
 
L

Lew

I'm not sure that's always true. I think the decision in COBOL 60 to
make the question of intermediate-result precision
implementation-dependent was wrong, period. The same with the decision
in ALGOL 60 not to define a usable syntax for machine use, or any kind
of I/O system.

Ah, I see your point. But "wrong" in the COBOL 60 case means "gave inaccurate
answers which cost money and trouble", so that is an engineering evaluation.
The term "wrong" is also overloaded with moral implications, which probably
are not relevant to the COBOL 60 issue either. I was in the latter semantic
space when I made my comment.

So I stand corrected, but propose that less emotionally charged words are more
appropriate to making engineering decisions, if only because they are less
conducive to misunderstanding. Or that we (meaning I) need to interpret such
words without emotional judgment while being as clear as possible in our (my)
speech.

A matter of putting Descartes before the hearts.

- Lew
 
L

Lew

Robbert said:
Ok, yes. If your goal is to allow programmers to specify which
exceptions a client must be prepared to handle, regardless of whether
these exceptions can occur in practice, the throws clause is not
redundant.

!

- Lew
 
P

Patricia Shanahan

Robbert Haarman wrote:
....
Ok, yes. If your goal is to allow programmers to specify which
exceptions a client must be prepared to handle, regardless of whether
these exceptions can occur in practice, the throws clause is not
redundant.

If your goal is to enumerate precisely which exceptions can be thrown by
some code, you would have to look at throw statements, and the throws
clause would be redundant (and, in Java's case, could make the compiler
force clients to write code to handle exceptions that cannot occur).

The throws clause specifies two things that together form a
contract:

A. The set of checked exceptions a client must be prepared to handle.

B. The set of checked exceptions an implementation is allowed to throw.

How would a compiler or documentation generator go about deducing the
list of exceptions that must be handled when calling a method in an
interface or non-final class? There may be code in an implementing or
extending class that does not yet exist, but that will be called by my
code some time in the future.

Looking at the other side of this, suppose I'm writing code to implement
an interface or extend a class. I need to know what exceptions I can use
without breaking any caller.

Patricia
 
R

Robbert Haarman

Because it is so useful.

...provided that you consider the ability to force clients to handle
exceptions that your code does not throw to be useful. Given the choice,
I'd rather be rid of the throws clause and lose that ability, but I do
see the value in the ability.

Regards,

Bob
 
J

John W. Kennedy

In re: throws

Wasn't Java "throws" copied (with a slight correction in English
grammar) from C++? And wasn't it put into C++ because of the
compatibility requirement that, absent an explicit "throw", C++
necessarily had an implicit "throw [anything]"?

For myself, I like having it. Now, it may make a difference that I do my
serious Java programming with Eclipse, which makes it trivially easy to
work with. And it keeps me from making stupid mistakes, and does it early.

(For whatever it's worth, I'm no clumsy novice with exceptions; I wrote
my first PL/I program in 1967.)
 
C

Chris Smith

Lew said:
Because it is so useful. You are supporting my point.

You aren't making a lot of sense. Given the current language design, I
add a throws clause whenever I want to pass an IOException through a
method. Are you claiming that I could catch and wrap all such
exceptions? If so, then that's why I qualified my statement with
"reasonable quality" code. Reasonable quality code doesn't fight
against the language design; so it doesn't wrap exceptions without
adding levels of abstraction, nor use custom exceptions to express ideas
that are better expressed using exceptions from the core library.
But from a syntactic and
semantic point of view, it is optional.

Again we're back to not particularly meaningful senses of the word
"optional".
If you are saying you cannot write a non-trivial program without handling
checked exceptions that someone else wrote, again I agree with you by and
large, but that is because the throws clause is doing exactly what it is
supposed to do. Those API writers were told that the throws clause would force
you to deal with certain exceptions. Now you are forced to deal with those
exceptions. It did what it was supposed to do.

The phrase "supposed to do" isn't particularly relevant here. Of course
the language is, by and large, implemented correctly, so everything does
what it's supposed to do. The question under discussion is whether a
different language design could provide the same substantial benefits
with less of the drawbacks. I think there have been two ways proposed
that it could: one is the inference of default throws clauses as
discussed here; the other (which pre-supposes first-class functions, so
is not really relevant to a Java-like language) is parameterizing the
feature so as to allow exceptions to be propogated from parameters to
their functions.
People, the throws clause exists to force you to deal with the checked
exceptions. Your complaint is that you are forced to deal with the exceptions
declared in the throws clause.

Well, my complaint in this subthread is that there is no inference
system to prevent me from having to declare them so often. Since I have
never been advocating ridding the language of this kind of validation, I
think it's a bit dishonest of you to say otherwise.
If you do not like it, do not blame the language for giving those API
designers too much power.

You are oversimplifying far too much to reasonably discuss the issue.
This kind of "take it or leave it" attitude may be relevant (if a little
rude) with regards to Java, but it guarantees that you will miss the
point with designing languages.
 
L

Lew

Chris said:
You aren't making a lot of sense. Given the current language design, I
add a throws clause whenever I want to pass an IOException through a
method. Are you claiming that I could catch and wrap all such
exceptions?
Yes.

If so, then that's why I qualified my statement with
"reasonable quality" code. Reasonable quality code doesn't fight
against the language design; so it doesn't wrap exceptions without
adding levels of abstraction, nor use custom exceptions to express ideas
that are better expressed using exceptions from the core library.

There are perfectly valid engineering reasons for wrapping exceptions and
rethrowing them as custom exceptions, or eating the exception and converting
to a non-exceptional value. It has to do with calling classes not caring any
more what the original exception is, if it was logged at the lowest point, but
only that an application-level exception occurred, or no exception if the
called method ate it.

These are design decisions that are natural to Java usage. There is nothing
"unreasonable" about the quality of these idioms.

Lew:
Chris Smith:
Again we're back to not particularly meaningful senses of the word
"optional".

It is a design decision to put the throws clause in, which is not required by
the language. That's about as optional as it gets.
The phrase "supposed to do" isn't particularly relevant here.

It's completely relevant. It is the core point. This whole discussion has been
about how to subvert the will of API writers who put checked exceptions in
their method interfaces.

Checked exceptions by design are supposed to force the caller to deal with
them. Complaining about having to deal with them is complaining about them
doing what they're supposed to.
The question under discussion is whether a
different language design could provide the same substantial benefits
with less of the drawbacks.

How would you give the API writer the power to force the calling class to deal
with the range of possible exceptions, at compile time?
I think there have been two ways proposed
that it could: one is the inference of default throws clauses as
discussed here;

Many folks on this thread have explained why this won't work the same way as a
throws clause.
the other (which pre-supposes first-class functions, so
is not really relevant to a Java-like language) is parameterizing the
feature so as to allow exceptions to be propogated from parameters to
their functions.

Interesting, that intrigues me.
Well, my complaint in this subthread is that there is no inference
system to prevent me from having to declare them so often.

Not needed. All you have to do is handle the exception at the lower level.

Letting the higher level know that the low level exception was IOException,
for example, is potentially breaking abstraction and encapsulation. There are
sound O-O reasons not to propagate exceptions up the chain always. If you do,
it's a design decision and you signal that by using the throws clause.
You are oversimplifying far too much to reasonably discuss the issue.

But the issue is exactly this simple. The whole point of the throws clause is
to give that power.
This kind of "take it or leave it" attitude may be relevant (if a little
rude)

Attitude? Everything I said was objective. It may have been mistaken,
misguided or false, but it was expository. Discuss the points on their merits.
with regards to Java, but it guarantees that you will miss the
point with designing languages.

I am not designing any languages. I am explaining what the throws clause is,
why it's useful, and what it provides, in Java. I am sure that another
language could do without this mechanism, and I do not know enough to know if
the throws clause is a Good Thing, but it has distinct and unique strengths
that are lost by every alternative suggestion presented on this thread so far.

I am not addressing whether those strengths are essential to programming in
general, or whether it is advisable to use checked exceptions. I am only
saying that the throws clause exists for the purpose of forcing exactly that
one must deal with checked exceptions at compile time in a way that guarantees
enforcement. No amount of inference at run time will provide that. In fact,
such run time inference causes clients to break if the API changes what
exceptions it throws between revisions. (This is the risk with unchecked
exceptions.)

Undoubtedly a language that didn't need such compile-time guarantees would not
have a throws clause. That is not Java.

Excoriating practices like rewrapping or eating exceptions is another issue.
You apparently oppose that practice. I aver that it is part of solid,
non-trivial, quality software design, if used in a solid exception-handling
strategy.

- Lew
 
C

Chris Smith

First things first,

Lew said:
I am not designing any languages. I am explaining what the throws clause is,
why it's useful, and what it provides, in Java.

That could explain a lot. This is a conversation about language design.
It has been, since the beginning. I have been perplexed for a while now
by your all-or-nothing approach. Are you really not interested in
discussing the language design perspective? If that's true, then you
need not respond.
Checked exceptions by design are supposed to force the caller to deal with
them. Complaining about having to deal with them is complaining about them
doing what they're supposed to.

At a deeper level, checked exceptions are designed to ensure that
exceptions are handled fruitfully. Ensuring that callers acknowledge
these exceptions is nothing more than a mechanism. There is just no
rational reason to desire, as an end in itself, a guarantee that all
immediate callers of this code acknowledge a potential exception. Such
a guarantee could be broken by a simple decomposition of the calling
function; and there ought to be a healthy skepticism by anyone toward a
language feature that ultimately intends to make illegal a simple
refactoring in some code in a completely different module.

Both of the two proposed changes mentioned here are attempts to preserve
the guarantee that errors are handled fruitfully, while relaxing the
requirement of their acknowledgement by every single method along the
way. If you are convinced that the ultimate goal is to force callers to
acknowledge exceptions, then I suppose you're sure to dislike them; but
again, I can't find a basis for such a goal.
Many folks on this thread have explained why this won't work the same way as a
throws clause.

Have they? Do you care to point me to anyone? I have read this thread
very closely, and I haven't seen anything.
Interesting, that intrigues me.

That was a different subthread. You're welcome to go read it. It ends
with a bit of Haskell code implementing the essence of such a checked
exception system.
Not needed. All you have to do is handle the exception at the lower level.

How nice of you to change my design for me... and too bad that I may
have liked the old one. All I'm talking about is removing a bit of
unnecessary wordiness; if you're proposing significant design changes as
an alternative, then I'm afraid you lose.
I am only
saying that the throws clause exists for the purpose of forcing exactly that
one must deal with checked exceptions at compile time in a way that guarantees
enforcement. No amount of inference at run time will provide that. In fact,
such run time inference causes clients to break if the API changes what
exceptions it throws between revisions. (This is the risk with unchecked
exceptions.)

Java doesn't currently prevent people from breaking the contracts of
public interfaces in any number of ways. In any case, I've already
mentioned that it would be fruitful to give a warning if throws clauses
are inferred for public methods of public types. The question is about
using inferred throws clauses for implementation artifacts, not for
public interfaces.
Excoriating practices like rewrapping or eating exceptions is another issue.
You apparently oppose that practice. I aver that it is part of solid,
non-trivial, quality software design, if used in a solid exception-handling
strategy.

You appear to be making the -- as far as I can tell, unjustified --
assumption that every time the language requires me to wrap an exception
to avoid declaring a throws clause, that it's also good for abstraction.
I see no reason to believe that will be the case. It's that assumption
of yours that I object to. Exception wrapping is perfectly acceptable
IF and ONLY IF it supports the abstractions in use. If it doesn't, then
it's worse than useless because you end up throwing the wrong exception
at the end.
 
R

Robbert Haarman

It is a design decision to put the throws clause in, which is not required
by the language. That's about as optional as it gets.

I believe I have kickstarted this discussion about whether or not the
throws clause is optional by referring to it as the "mandatory throws
clause". Perhaps I should explain what I meant by that.

The throws clause is mandatory in Java if your method may throw a
certain exception. E.g.

void foo() { throw new IOException("Bogus"); }

is wrong; you have to write

void foo() throws IOException { throw new IOException("Bogus"); }

Similarly, a method that used foo but did not catch the IOException
could not be writtn like

void bar() { foo(); }

but would have to be written

void bar() throws IOException { foo(); }

instead.

This is what I meant by the throws clause being mandatory.

Qualifying the throws cluase as being mandatory makes sense, because it
could also not be mandatory. Various examples of this have been
mentioned throughout the discussion.

Now, I understand Lew as saying the throws clause is optional. His
justification for saying so is that it is up to the programmer to write
his code in such a way that it does not require a throws clause. For
example, foo could have been written

void foo() { throw new RuntimeException("Bogus"); }

or bar could have been written

void bar() {
try {
foo();
} catch(IOException ioe) {
throw new RuntimeException(ioe.getMessage());
}
}

or any number of other ways that do not require the throws clause to be
added.

I believe we are both correct, but we're talking about different things.
Lew is saying that, with everything that is possible in Java, it is
possible to avoid having to write a throws clause. Thus, the clause is
optional.

I am saying that, in the specific situation where your method allows an
exception to "escape" that someone up the chain must handle, Java
requires you to write a throws clause. I.e. the throws clause is
mandatory _in that specific situation_.

I hope this clears up some of the confusion.

Regards,

Bob
 
C

Chris Uppal

Lew said:
This whole discussion has
been about how to subvert the will of API writers who put checked
exceptions in their method interfaces.

I can hardly remember /any/ of this thread which discussed that matter -- it
has (with very few exceptions) been accepted as axiomatic that /if/ an API
designer warns you that <some condition> is possible and should be checked for,
that you will wish to do so, and (furthermore) that you will wish to have the
compiler tell you when you forget.

The debate isn't about how to circumvent the wishes of the API designer, but
about:

1) How best to allow designers to communicate the requirements.

2) How allow the composition of such requirements from different APIs without
unnecessarily constraining each individual designer's options.

3) How to optimise the syntactic load on both the users and implementers of
APIs.

(There may have been other stuff too -- but those are the main themes as I see
it.)

And, once again, the discussion isn't about how to make best use of Java as it
is currently designed, but about how best to design a language -- current Java
is relevant only as a source of input to that discussion.

-- chris
 
C

Chris Uppal

Chris Smith wrote:

[me:]
If bbb were exposing its relationship with inner, then that would be
breaking abstraction. That's not what's going on, though. bbb is
making the (true) statement that it can fail in certain ways. Whether
it can fail that way because it calls inner or for some other reason, is
immaterial and is properly hidden behind an abstraction boundary.

It's is exposing a failure mode to aaa() despite the fact that neither it nor
aaa() necessarily have any interest in that failure mode. Consider the earlier
example of a file-backed implementation of java.util.List. Neither List itself
(or AbstractList) nor most code that /uses/ List has any interest in the IO
failures that my implementation may throw. There is no relationship between,
say, List.add() and (say) Collections.fill() to which my class is even
/visible/ let alone relevant. So, in particular, the failure modes of my
implementation cannot be part of the contract between those methods.

If you want to claim that there is a contractual relationship between them then
either (a) my desire to create a file-backed implementation of List is
inherently absurd, or (b) the designers of java.util.List screwed up by not
including IOException among the exceptions that add() is declared to throw.

If we take the second option, that the designers /should/ have declared add()
to throw IOException, then clearly List is coupled to my implementation (or at
least to the space of possible implementations) -- which I call a break in
abstraction. I'm sure you don't think that List.add() ought to declare
IOException -- but that's what javac thinks.

The contract is (should be) between the place where the exception is generated
and the place where the exception is (intended) to be handled. In this case
that would be code (somewhere outside java.util) which /used/ my FileBackedList
object. But Java is unable to police that contract, so it insists on treating
it as if it were duplicated between every caller/callee pair on the invocation
trail. Thus involving each of them with the bottom-most rung on that ladder,
and (by doing so) breaking encapsulation.

I'm not saying there aren't cases where the real responsibility /is/ passed
from hand to hand like that (not skipping intermedate rungs), but such cases
(though common) are not the universal rule.

The "callback" examples, elsethread, are just one special case of this.

What if the "Architect" has forgotten to do so?

That's why I accept the need for computer-aided policing. There is, from the
computer's point of view, no difference between "the architect has forgotten to
specify a place where Xxxx /should/ be handled" and "the specified place
doesn't contain a handler for Xxxx".

Or at least, there's no difference in a Java-like system -- it might be
interesting to see if there's any mileage in abstracting away from a scattergun
sprinkling of try{}catch{} blocks into something with more overt structure.

-- chris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top