Some source code modifications, such as removing a method from a class, are binary incompatible changes in the sense that other programs which work fine with the old binary may cease to function when linked with the evolved new binary due to the removal of the method. However, the safety of modern software systems demands that under no circumstances may an application crash. The JLS requires that, under the incompatible change in which a method is removed, the program should still run as long as the missing method is not used, and that an exception should be raised if code tries to invoke the missing method at run time.
Consider what happens when we remove the method eat from class Programmer in the original program and recompile it. The vtables for Programmer and JavaProgrammer are shown in Figure 3. Obviously, the vtable layout of class Programmer has changed, and it is no longer consistent with the vtable layout of class JavaProgrammer.
public class Programmer { // void eat () { ... }; // Removed! void hack () { ... }; }In this case, the correct behavior of a virtual method invocation obj.eat in any old binary depends on the static class of the object obj. If the static class of obj is JavaProgrammer, the method invocation works fine, as if no change had been made. However, if the static class of obj is Programmer, a NoSuchMethodError exception should be thrown when the method is invoked, even if obj actually contains an object of class JavaProgrammer which defines method eat.
The standard vtable approach fails in this case as well. The invocation Tom.eat in Manager will call the wrong method hack, while Tom.hack will have implementation-dependent results, since it uses a pointer located outside of the actual vtable.
The observation here is that we need to gracefully handle incompatible changes by raising exceptions at run time. Of course, we still need to keep in mind the consistency of vtables.