gnu-arch-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Gnu-arch-users] Nit


From: Tom Lord
Subject: Re: [Gnu-arch-users] Nit
Date: Tue, 21 Oct 2003 17:53:48 -0700 (PDT)


    > From: Dustin Sallings <address@hidden>

    >> It must be handled _somewhere_up_the_call_graph_.  It must be in the
    >> throws list of my method.  But Java does _not_ require that it be
    >> handled at the call-site.  It's that distinction that is at issue.

    >   I understand what you're saying about throws-per-call, and it sounds 
    > like an interesting idea, but as you say, it isn't much different from 
    > return values.  I believe this reduces the value.

    >   To be concrete:

    >   public List getLinesOfFile(String f) throws IOException {
    >           String realFile=translatePath(f);
    >           InputStream is=openTheStream(realFile);
    >           List rv=getLinesOfStream(is);
    >           is.close();
    >           return(rv);
    >   }

    >   In the above example, each of openTheStream, getLinesOfStream, and 
    > close() may raise an IOException.  translatePath looks up its mapping 
    > in an internal Map, and if the value is not found, returns the passed 
    > value.  (For clarity, I've left out the finally block to deal with 
    > is.close().  If you're uncomfortable with that, assume the frequency of 
    > this method call is small enough that the stream finalization is 
    > sufficient).

That's very close to what cduffy just posted.

    >   However, we've found that our translation map is too large and now has 
    > to use a cdb or something to perform the translation.  Now, 
    > translatePath may also throw an IOException which was previously not an 
    > expected failures state.

    >   The question, then, is whether translatePath()'s exception causes the 
    > program to be incorrect now.  I do not believe it does.  

Perhaps so, but that's very specific to the particularly generic
exception, IOException, that you've chosen for the example.

It sounds like IOException is so general in nature in this
hypothetical that you should be able to declare it as unchecked.

A more specific error, like NoSuchUser, isn't going to have so broad a
meaning that it won't matter from where in the processing it was
returned.

So, hmm..... I guess in "Tom's Repaired Java" these things would be
the case:

        1) You could declare IOException to be unchecked.

        2) In the code above, all four methods (translatePath,
           openTheStream, getLinesOfStream, and close) would have
           to have the same `throws' list of checked exceptions.

        3) The list of checked exceptions in the throws of
           getLinesOfFile would have to be the same as that of the
           four called methods.

The annoyance would be this:

Suppose that three of the four called methods can return a checked
exception of type GopherHole but that the close method can not (at the
time you compile your code).  You would have to write (and, again,
please excuse my inevitable Java syntax errors):


        public List getLinesOfFile(String f) throws GopherHole {
                String realFile=translatePath(f);
                InputStream is=openTheStream(realFile);
                List rv=getLinesOfStream(is);
                try {
                  is.close();
                } catch (SomeClass e) {
                  .....stuff....
                }
                return(rv);
        }

where SomeClass is, or is a superclass of, GopherHole.


    >   This is the contract of this method.  It will return a List,
    > or an excuse via an IOException.  If the caller needs more
    > information than what's provided by the published API, it's an
    > abstraction leak.

"contracts of methods" -- that's maybe a good way to restate it again.

The problem with the current rules in Java is that you can write a
method call, compile it with one contract, then modify one of the
modules it imports, recompile that, and, violating the original
contract implicit in the method call, link everything together and
run.   Current Java is just fine with that -- it doesn't reliably
enforce the original contract.

In my rewrite of getLinesOfStream, if you dropped the `try' around the
call to close, I guess the compiler would give an error message like:

         ERROR(foo.java:234):     is.close();
                                  ^
           Changes to the called method's throws declaration may break
           the exceptions contract of this call.  A `try' clause
           catching (possibly superclasses of) these classes is
           suggested:

                        GopherHole


-t






reply via email to

[Prev in Thread] Current Thread [Next in Thread]