Wednesday, 19 September 2012

Puzzle 68: Shades of Gray


This program has two declarations of the same name in the same scope and no obvious way to choose between them. Does the program print Black? Does it print White? Is it even legal?
public class ShadesOfGray {

    public static void main(String[] args){

        System.out.println(X.Y.Z);

    }

}



class X {

    static class Y {

        static String Z = "Black";

    }

    static C Y = new C();

}



class C {

    String Z = "White";

}


Solution 68: Shades of Gray

There is no obvious way to decide whether this program should print Black or White. The compiler generally rejects ambiguous programs, and this one certainly appears ambiguous. Therefore, it seems only natural that it should be illegal. If you tried it, you found that it is legal and prints White. How could you possibly have known?
It turns out that there is a rule that governs program behavior under these circumstances. When a variable and a type have the same name and both are in scope, the variable name takes precedence [JLS 6.5.2]. The variable name is said to obscure the type name [JLS 6.3.2]. Similarly, variable and type names can obscure package names. This rule is indeed obscure, and any program that depends on it is likely to confuse its readers.
Fortunately, programs that obey the standard Java naming conventions almost never encounter this issue. Classes begin with a capital letter and are written in MixedCase, variables begin with a lowercase letter and are written in mixedCase, and constants begin with a capital letter and are written in ALL_CAPS. Single capital letters are used only for type parameters, as in the generic interface Map<K, V>. Package names are written in lower.case [JLS 6.8].
To avoid conflict between constant names and class names, treat acronyms as ordinary words in class names [EJ Item 38]. For example, a class representing a universally unique identifier should be named Uuid rather than UUID, even though the acronym is typically written UUID. (The Java platform libraries violate this advice with such class names as UUID, URL, and URI.) To avoid conflicts between variable names and package names, don't use a top-level package or domain name as a variable name. Specifically, don't name a variable com, org, net, edu, java, or javax.
To remove all ambiguity from the ShadesOfGray program, simply rewrite it to obey the naming conventions. It is clear that the following program prints Black. As an added bonus, it sounds the same as the original program when read aloud.
public class ShadesOfGray {

    public static void main(String[] args){

        System.out.println(Ex.Why.z);

    }

}



class Ex {

    static class Why {

        static String z = "Black";

    }

    static See y = new See();

}



class See {

    String z = "White";

}


In summary, obey the standard naming conventions to avoid conflicts between different namespaces (and because your program will be illegible if you violate these conventions). Also, avoid variable names that conflict with common top-level package names, and use MixedCase for class names even if they are acronyms. By following these rules, you'll ensure that your programs never obscure class or package names. Yet again, this is a case of the general rule that you should avoid name reuse except for overriding. For language designers, consider eliminating the possibility of obscuring. C# does this by putting fields and nested classes into the same name space.

No comments:

Post a Comment

Your comments are welcome!