more on backward compability – this time with lang

I blogged an answer to Mark’s question about var in Java 10. He wrote back the following. I thought it was great and asked if I could use it as a guest blog post. He said yes.

So compliments of our guest blogger: Mark Yagnatinsky.

Thanks! You inspired me to try compiling my own little test program that I’d wondered about for a while:

It turns out that if you try to do this:

class java {
    class lang {
    }
}

Java won’t let you (it notices that there’s already a package with that name).
But first of all, this protection extends only to java.lang, and not, say, java.util.
And second of all, we can distract it by putting our code in a package:

package Scratches;
class java{
    interface lang{
        class String{}
        static void main( HELP[] args ) {
        }
    }
}

As far as I can tell, there is nothing we can type instead of HELP to make the above main method runnable on the command line.
In this case though, we’re only doing “local” damage: the rest of the code in our package (outside of “interface lang”) can still use Strings.

The way this is usually described is that there is an implicit “import java.lang.*” at the start of every file.
It turns out that java.lang is more special than this description implies.

If we try the same trick with java.util, we can knock access to the entire package (but not subpackages):

package Scratches;
// the line below has no effect whether you comment it out or not.
//import java.util.Hashtable;
class java {
    interface lang {
        class String{}
        static void main( String... args ) {
            // can't fix signature to run this method.
        }
    }
    interface util {
        class Hashtable{}
    }
}
class Main {
    public static void main( java.lang.String... args ) {
        // this method does not get called if you run from the command line
    }
    public static void main( String... args ) {
        // this method runs from the command line just fine
        new java.util.Hashtable(); // this is our hash table, not Java's
        // the line below won't compile (no such name)
        //new java.util.HashMap();
        new java.util.concurrent.ConcurrentHashMap(); // but this is fine
    }
}

It’s kind of amazing how much insanity the capitalized class name convention protects us from.
(Though to be fair, Java.Util is also a fairly unlikely class name…)