Exceptions

Exceptions in Meso can be thrown and caught with the same syntax as that in Java. There difference is what can be thrown as an exception, and how to distinguish checked and unchecked exceptions.

The IMOP protocol allows any object to be thrown as an exception. A structure value can also be thrown as an exception, which will be discussed latter. We made this design choice because it doesn't seem viable to mandate all IMOP exception types to inherit from one particular IMOP UTL similar to java.lang.Throwable in Java ― whoever hosts that UTL's definition will become the bottleneck of the entire world.

For the same reason, we cannot distinguish a checked or unchecked exception based on its type. Instead, we distinguish them based on the method signature where the exception is thrown. An exception is a checked exception If it is declared in the throws clause of the method; otherwise it is unchecked. A checked exception must be explicitly caught or thrown outward in the Meso language.

For example, assume that example.com uses this imop: interface type for its exceptions:

namespace imop:example.com/foo;

public interface MyException {

   // ...
}

And it creates a meso: class implementing the interface:

namespace meso:foo;
import imop:example.com/foo.MyException;

public class MyExceptionImpl implements MyException {

   // ...
}

This is how an exception can be thrown over an IMOP connection:

namespace imop:example.com/foo;
import meso:foo.MyExceptionImpl;

public object MyService {

   public void func() {

      // do something nasty

      throw new MyExceptionImpl();   // unchecked exception
   }
}

Since the MyExceptionImpl type is not declared in a throws clause of the func() method, it is regarded as an unchecked exception. Also notice that even though MyExceptionImpl is a meso: class, it implements an imop: interface type, and therefore the newly created object can be passed over the IMOP connection. (Check this page for more information on this.)

Since it is an unchecked exception, the client side might not be aware of it. For example:

namespace meso:;
import imop:example.com/foo.MyService;

public class Client {

   public static void main(string[] args) {

      MyService.func();    // will throw unchecked exception
   }
}

Execute this client and you will see:

stefan@macpro:~/local$ java -jar meso.jar -cf config.xml meso:Client
Exception 'imop:example.com/a1b2c3d4e5' is thrown
stefan@macpro:~/local$ _

The UTL imop:example.com/a1b2c3d4e5 is a dynamically generated reference to the IMOP object implementing the imop:example.com/foo.MyException interface.

The client may want to catch all IMOP exceptions with imop:ref at some point in the program to prevent uncaught exception from stopping the program:

namespace meso:;
import imop:example.com/foo.MyService;

public class Client {

   public static void main(string[] args) {

      try {
         MyService.func();

      } catch (imop:ref err) {       // catch everything

         // do something to handle the error
      }
   }
}

example.com can let its clients know that such exception may occur by declaring it as a checked exception:

namespace imop:example.com/foo;
import meso:foo.MyExceptionImpl;

public object MyService {

   public void func() throws MyException { // now MyException is checked exception

      // do something nasty

      throw new MyExceptionImpl();   // checked exception
   }
}

If a client program calls the function without dealing with the checked exception like so:

namespace meso:;
import imop:example.com/foo.MyService;

public class Client {

   public static void main(string[] args) {

      MyService.func();    // may throw checked exception
   }
}

Then one will get a compile time error message showing that the exception is not handled:

stefan@macpro:~/local$ java -jar meso.jar -cf config.xml meso:Client
Syntax error in source /Users/stefan/local/Client.meso:
[8,20 - 25] Unhandled exception type imop:example.com/foo.MyException
stefan@macpro:~/local$ _

Just like Java, one may handle the checked exception by using a try/catch block or adding a throws clause to the enclosing method.

Throwing a structure value as an exception

Objects are all passed by reference in IMOP, so throwing an object instance as an exception is really just passing a UTL to the object; the receiver must make additional calls to the object to figure out what the error is about. This may be inappropriate for certain kinds of error when the server really can't or don't want to respond to the client anymore. This is why we also allow structure value to be thrown as exceptions, since the entire structure value is serialized and sent over the connection. The client can look into the structure value directly without interacting with the server.

There is no equivalent of imop:ref for structure types that can represent all of them, therefore structure type exceptions cannot be thrown as an unchecked exception. They must all be declared as checked exceptions from the method signature.