Wednesday, 19 September 2012

Puzzle 72: Final Jeopardy


This puzzle examines what happens when you attempt to hide a final field. What does this program do?
class Jeopardy {

    public static final String PRIZE = "$64,000";

}



public class DoubleJeopardy extends Jeopardy {

    public static final String PRIZE = "2 cents";

    

    public static void main(String[] args) {

        System.out.println(DoubleJeopardy.PRIZE);

    }

}


Solution 72: Final Jeopardy

Because the PRIZE field in Jeopardy is declared public and final, you might think that the language would prevent you from reusing this field name in a subclass. After all, final methods cannot be overridden or hidden. If you tried the program, you found that it compiles without a hitch and prints 2 cents. What went wrong?
It turns out that the final modifier means something completely different on methods and fields. On a method, final means that the method may not be overridden (for instance methods) or hidden (for static methods) [JLS 8.4.3.3]. On a field, final means the field may not be assigned more than once [JLS 8.3.1.2]. The keyword is the same, but the behavior is unrelated.
In the program, the final field DoubleJeopardy.PRIZE hides final field Jeopardy.PRIZE, for a net loss of $63,999.98. Although it is possible to hide fields, it is generally a bad idea. As we discussed in Puzzle 66, hiding fields can violate subsumption and confound our intuition about the relationship between types and their members.
If you want to guarantee the prize in the Jeopardy class even while preserving the ability to subclass it, use a final method instead of a final field:
class Jeopardy {

    private static final String PRIZE = "$64,000";



    public static final String prize() {

        return PRIZE;

    }

}


For language designers, the lesson is to avoid reusing the same keyword for unrelated concepts. A keyword should be reused only for closely related concepts, where it helps programmers build an intuition about the relationship among the language features in question. In the case of the Java's final keyword, reuse leads to confusion. It should be noted that as a language ages, there is a natural tendency to reuse keywords for unrelated concepts. This avoids the need to introduce new keywords, which is enormously destabilizing. When language designers do this, they are generally choosing the lesser of two evils.
In summary, avoid reusing names for unrelated variables or unrelated concepts. Using distinct names for unrelated concepts helps readers and programmers to keep the concepts separate.

No comments:

Post a Comment

Your comments are welcome!