The Source for Java Technology Collaboration
User: Password:



Rémi Forax

Rémi Forax's Blog

Function that does not return normally

Posted by forax on August 26, 2006 at 08:04 AM | Comments (14)

It's a recurring problem, you have a code that always generates an exception
   public void throwIOException(int code) throws IOException {
     throw new IOException(IO.getMessage(code));
   }
  
and you use it in a method like this :
   public int read() throws IOException {
     int value=readAByte()
     if (value!=-1)
       return value;
     throwIOException(IO.errorCode);
   }
  

Because there is no way to say to the compiler something like "hey, the method throwIOEXception doesn't return", the compiler emit an error because the method read() could return without a value.

In the now famous closure proposal, there is a small section titled "The type of null" that i understand like this: if you use null as return type, you can indicate that the method never return.

   public null throwIOException(int code) throws IOException {
     throw new IOException(getMessage(code));
   }
  

Pretty cool !

update: see Function that does not return normally II (the return) for the part2 of this entry.


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • hmm, this is weird. So this is a way of stating that a method always throws an Exception?

    leouser

    Posted by: leouser on August 26, 2006 at 08:23 AM

  • I have always returned the exception rather than throwing it. You can therefore write:


    public int read() throws IOException {
    int value=readAByte()
    if (value != -1) {
    return value;
    }
    throw createIOException(IO.errorCode);
    }

    The compiler is happy, and the code is more obvious.

    It's not quite so nice if multiple exception types can be thrown. In that case I've thrown the exception but declared the return type as Error (an unconstructable, final subclass of Error is also a nice choice). The compiler is happy and we can still see that it throws an exception (even if the how is a slightly obscured).

    Posted by: tackline on August 26, 2006 at 08:29 AM

  • This looks like a job for Void.class

    Posted by: jessewilson on August 26, 2006 at 01:38 PM

  • Your method should claim to return a value, then everything falls into place.


    public R throwIOException(int code) throws IOException {
    throw new IOException(IO.getMessage(code));
    }

    public int read() throws IOException {
    int value=readAByte()
    if (value!=-1)
    return value;
    // may have to give explicit type parameter for a primitive here
    return throwIOException(IO.errorCode);
    }

    Posted by: mernst on August 27, 2006 at 01:33 AM

  • Darn HTML input. There is supposed to be a <R> type parameter on throwIOException.

    Posted by: mernst on August 27, 2006 at 01:35 AM

  • Sorry for spamming, but this way, the code gets much shorter, too:

    return (value != -1) ? value : IO.<Integer>throwIOException(-1);

    Posted by: mernst on August 27, 2006 at 04:27 AM

  • Ok, my example is no so good.

    So let me take another one, the treatment of exceptions like InvocactionTargetException, ExecutionException or SAXException.
    These exceptions are basically wrappers of RuntimeException
    and in order to propagate their cause i have to write
    something like this :

    try {
    method.invoke(blahbblah);
    } catch(InvocationTargetException e) {
    Throwable cause=e.getCause();
    if (cause instanceof RuntimeException)
    throw (RuntimeException)cause;
    if (cause instanceof Error)
    throw (Error)cause;
    throw new AssertionError(cause);
    }

    Because there is no way to say "this method never returns",
    i can't write something like this :

    public null rethrowCause(Throwable cause) {
    if (cause instanceof RuntimeException)
    throw (RuntimeException)cause;
    if (cause instanceof Error)
    throw (Error)cause;
    throw new AssertionError(cause);
    }

    I don't see another way to express that.

    Rémi

    Posted by: forax on August 27, 2006 at 05:42 AM

  • jessewilson - agreed!

    Posted by: phlogistic on August 27, 2006 at 09:56 PM

  • phlogistic & jessewilson : I agree that using Void.class as return type seems to be a better solution than changing the language syntax. But despite this particular class is uninstantiable, a method that would be defined with such a return type would be expected to return a reference. That is not the case with a "null" keyword that would finally make things more clear.

    Posted by: micf on August 28, 2006 at 02:31 AM

  • I would think that calling a method known to never return a value would still be flagged by the compiler. Saying that the method returns "null" doesn't take away the explicit requirement that the calling method needs to return something.


    I vote for an explicit throw in the caller (and the called method just returns an exception to use) or a syntax that says a given method always throws (and I lean toward this latter option, if possible):


    public exception throwIOException(int code) throws IOException...

    public @exception throwIOException...

    @AlwaysThrows public void throwIOException...

    @AlwaysThrows(IOException)
    public void throwIOException...

    Posted by: headius on August 28, 2006 at 12:35 PM

  • In the most recent javaposse podcast they suggested an annotation for this case. That would be like the @AlwaysThrows idea ... However, is it correct to say the method never returns in this case? The method call is terminated when the exception occurs, and isn't that termed an abnormal return as opposed to a normal return using the return statement?

    Posted by: robogeek on August 28, 2006 at 03:09 PM

  • I think we're abusing exceptions for control logic here...is it a really an exception condition if we call a method that does nothing but the exception?

    Posted by: phlogistic on August 28, 2006 at 07:42 PM

  • phlogistic : I guess the goal of this method is to write once a throw statement that is reused at several locations. This method may still be called only for an exception condition.

    Posted by: micf on August 29, 2006 at 01:21 AM

  • A closure that does not return normally has a return type of null, but the converse is not true. A function (or method) that returns null can return normally, returning the value null. The caller cannot assume that won't happen.

    Posted by: gafter on September 06, 2006 at 11:15 PM



Only logged in users may post comments. Login Here.


Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds