There are a number of possible ways we can be "backwards compatible" and some of them are easier to manage than others.

Since the original post/comment was about Java 7, I'm going to use "Java 6" to mean the "old" version of Java that we're trying to stay compatible with and "Java 7" to refer to the new, perhaps incompatible version. And I'll use closures as an example of a feature in Java 7 that may interfere with compatibility. You can substitute in your own features and version numbers if you wish.

As best I can identify, the various ways to preserve backwards compatibility are:

At the binary level

1. Source written in Java 6 can be recompiled for Java 7 For some people, this may be enough. Ditch any plans to keep running existing class files, throw away your binary jar files (or run them through a Java 7 converter), and recompile everything from source. It's more or less what Android is (although it hasn't added a new alternate syntax). However, it means that the new VM can't run old applets (for the devoted few who still care about applets) and it also means that you can't download a jar file from the internet and use it in your app unless you know whether it's a Java 6 jar file, or a Java 7 jar file. In practice we already have that problem. Java 5 jar files don't run on a Java 4 VM. But this would create the reverse - Java 6 jar files won't run on Java 7 VMs and Java 7 jar files won't run on Java 6 VMs. The only extent to which this can be considered to be "backwards compatible" is that you don't have to throw away your existing source code. You can make it run on the new VM (with a small amount of effort)

2. Old applications run unchanged on new VMs At its simplest, that just means that the Java 7 VM has support for running a pure Java 6 application. It's a bit like the Playstation 2 being compatible with the original Playstation - it had a PS1 embedded in it so it could play PS1 games. However, since JEE deployments are a significant focus on the java landscape, we probably need to extend the definition of an application to include anything packaged as an EAR or WAR file. Which means we need app servers that can run Java 6 applications as well as Java 7 applications. Presumably at the same time. The main complexity in that is the consequences for rt.jar. Does the VM need to expose a single version of rt.jar that is compatible with both Java 6 and Java 7 applications? Would it be possible for an app server running on a Java 7 VM to provide different versions of rt.jar to the different applications? Or would we need to have an rt.jar with a java.util package and a java7.util package? (The latter of which has serious consequences for the other possible definitions of "backwards compatible")

3. Old class files can be used by new class files (written in Java 7) This would mean that your new Java 7 source code would be able to use the existing jar file for your JDBC driver. It means that as far as Java 7 is concerned we need

  1. A VM that can run Java 6 class files alongside Java 7 class files
  2. A calling method from a Java 7 class file to a method in a Java 6 class file

4. Old class files can call methods on Java 7 classes If you want to be able to write a ListModel in Java 7, and then pass that to a swing component written in Java 6, then you need this. To do it properly, it means that the Java 6 code can use reflection on the Java 7 class, and get meaningful data back. The class file format may not need to be anything like the Java 6 class file format, but the reflection APIs and classloaders need to be able to hide the differences. This form of compatibility was one of the requirements that impacted generics.

At the source level

5. The Java 7 version of "javac" knows how to compile both Java 6 and Java 7 code This is easy. The Groovy compiler already does this - you just need a way to work out which syntax is being used in a source file.

6. Source that uses the Java 7 syntax can call methods on Java 6 classes This is pretty simple to do. The new syntax needs a way to invoke a Java 6 method, but the various "new" syntaxes being played with (Groovy, Scala, etc) already support this (although as Gilad Bracha's recent post on static variables points out, it has constrained the design of those languages).

7. Source that uses the old Java 6 syntax can call methods on new Java 7 classes This is fairly straight forward if you're happy to require that it's compiled with the new compiler. You need to decide what to do about classes that use new features. E.g. What if Java 6 code calls a method that returns a closure? If the Java 6 syntax has no way to represent that closure, then we have a problem.

8. Source written in Java 6 can have Java 7 features added to it slowly This would require that every Java 6 source file is also a valid Java 7 source file. It means that I can have a single source file, defining a single class, and one of the methods (that was written years ago) uses the old Java 6 syntax, while another method (that I wrote today) uses the new Java 7 syntax. And they live happily together in the same file.

I think we're likely to find different people care about different definitions for "backwards compatibility", and there will be some people who think we need to support all of them.

My personal opinion is that if you don't have #1, #2, #3, and #6 then it's not Java. Not having #7 (and probably #4 too) will seriously restrict the number of people that are willing to switch. Point #5 is easy to do (as groovy has shown) and useful enough that you'd be stupid not to do it.

So really the point to question is #8. And while it's useful, and I think we'd all like to keep it, the question has to be "Is it important enough to hold back the evolution of the language (and platform) ?"