These days, on my spare time, I dive into Python. Well, I am still in the air at this time with only my fingers in the water. But the water is very welcoming.
Introspection
Python makes introspection simple. As I read about it, I remembered how Java's introspection and reflection APIs can sometimes give headaches. These headaches are in fact indirectly caused by Java's checked exceptions (There are many discussions about advantages or disadvantages of checked exceptions in Java as opposed to unchecked exceptions in Python.)
When using reflection to invoke methods, if the method invoked throws any exception, this exception is wrapped inside a java.lang.reflect.InvocationTargetException before returning from the invoke call. This also applies to instantiation methods (newInstance for example). But often, you will bump into code that looks like this:
1 ...
2 try {
3 ...
4 method.invoke(object, args);
5 ... // do other stuff that may throw SomeException
6
7 } catch(SomeException e){
8 // do something special about this exception
9 } catch (Throwable e){
10 // do something else
11 }
12 ...
If the invoked method throws SomeException, the caught exception at line 7 will not catch it. The exception that will pop up here will be an InvocationTargetException that embeds SomeException. To behave as expected, this code should be minimally rewritten as:
1 ...
2 try {
3 ...
4.1 try {
4.2 method.invoke(object, args);
4.3 } catch(InvocationTargetException e){
4.4 throw e.getTargetException();
4.5 }
5 ... // do other stuff that may throw SomeException
6
7 } catch(SomeException e){
8 // do something special about this exception
9 } catch (Throwable e){
10 // do something else
11 }
12 ...
With this change, we rethrow the exception thrown from the invoked method. This exception is then caught as expected at line 7.
Of course, the first code excerpt is not good code even if it compiles without warnings: It is not recommended to place a lot of code inside a try/catch block. If we had been careful in catching exceptions along the way, but without paying attention to the InvocationTargeException, we may have written this:
1 ...
2 try {
3 method.invoke(object, args);
4 } catch(SomeException e){
5 // do something about SomeException
6 } catch (Throwable e){
7 // do something else
8 }
9 try {
10 ... // do other stuff that may throw SomeException
11 } catch(SomeException e){
12 // do something special about this exception
13 } catch (Throwable e){
14 // do something else
15 }
16 ...
Once written, you compile it and boom!, there is an error at line 4: SomeException is never thrown in try block. Or something like that. Using a better programming style would have caused the error to be identified early: we would have wondered why this does not compile and soon realize that the invoke method throws a InvocationTargetException which may embed SomeException. We would have changed code according to this fact at compile time, which is a good thing.
Java has forced checked exceptions on us programmers with the hope to see better code out there. As a result, it is harder to write good code and laziness being such a strong force of nature, we take short cuts with traps that hide bugs. And these bugs can take a lot of time to identify.
+1 to Python in this domain.