Friday, March 12, 2010

Well, Dog My Cats!

Well, Dog My Cats!

This program uses a Counter class to keep track of how many times each kind of house pet makes a noise. What does the program print?

class Counter {

private static int count;

public static void increment() { count++; }

public static int getCount() { return count; }

}



class Dog extends Counter {

public Dog() { }

public void woof() { increment(); }

}



class Cat extends Counter {

public Cat() { }

public void meow() { increment(); }

}



public class Ruckus {

public static void main(String[] args) {

Dog dogs[] = { new Dog(), new Dog() };

for (int i = 0; i < dogs.length; i++)

dogs[i].woof();

Cat cats[] = { new Cat(), new Cat(), new Cat() };

for (int i = 0; i < cats.length; i++)

cats[i].meow();

System.out.print(Dog.getCount() + " woofs and ");

System.out.println(Cat.getCount() + " meows");

}

}






Solution : Well, Dog My Cats!


We have two dogs woofing and three cats meowing—a ruckus, to be sure—so the program should print 2 woofs and 3 meows, no? No: It prints 5 woofs and 5 meows. Where is all the extra noise coming from, and what can we do to stop it?



The sum of the number of woofs and meows printed by the program is 10, fully twice what it should be. The problem is that Dog and Cat inherit the count field from a common superclass, and count is a static field. A single copy of each static field is shared among its declaring class and all subclasses, so Dog and Cat use the same count field. Each call to woof or meow increments this field, so it is incremented five times. The program reads it twice, by calling Dog.getCount and Cat.getCount. In each case, 5 is returned and printed.



We cannot fix the problem by making count an instance field. That would create one counter per pet rather than one counter per kind of pet. To fix the program, we must correct a fundamental design error.



When designing one class to build on the behavior of another, you have two options: inheritance, in which one class extends the other; or composition, in which one class contains an instance of the other. Choose based on whether each instance of one class is an instance of the other class or has an instance of the other. In the first case, use inheritance; in the second, use composition. When in doubt, favor composition over inheritance .



Neither a dog nor a cat is a kind of counter, so it was wrong to use inheritance. Instead of extending Counter, Dog and Cat should each have a counter field. One counter is required for each kind of pet, rather than for each individual pet, so these fields must be static. We needn't bother with a Counter class; an int will do fine. Here is the redesigned program, which prints 2 woofs, 3 meows as expected:




class Dog {

private static int woofCounter;

public Dog() { }

public static int woofCount() { return woofCounter; }

public void woof() { woofCounter++; }

}



class Cat {

private static int meowCounter;

public Cat() { }

public static int meowCount() { return meowCounter; }

public void meow() { meowCounter++; }

}



The Ruckus class is unchanged with the exception of the two print statements, which are modified to use the new method names to access the counts:




System.out.print(Dog.woofCount() + " woofs, ");

System.out.println(Cat.meowCount() + " meows");



In summary, static fields are shared by their declaring class and any subclasses. If you need a separate copy of a field for each subclass, you must declare a separate static field in each subclass. If you need a separate copy for each instance, declare a nonstatic field in the base class. Also, favor composition over inheritance unless the derived class really is a kind of the base class.

Saturday, March 6, 2010

What's the Point?

What's the Point?

This program has two immutable value classes, which are classes whose instances represent values. One class represents a point on the plane with integer coordinates, and the second class adds a bit of color to the puzzle. The main program creates and prints an instance of the second class. What does the program print?

class Point {

private final int x, y;

private final String name; // Cached at construction time



Point(int x, int y) {

this.x = x;

this.y = y;

name = makeName();

}



protected String makeName() {

return "[" + x + "," + y + "]";

}



public final String toString() {

return name;

}

}



public class ColorPoint extends Point {

private final String color;



ColorPoint(int x, int y, String color) {

super(x, y);

this.color = color;

}



protected String makeName() {

return super.makeName() + ":" + color;

}



public static void main(String[] args) {

System.out.println(new ColorPoint(4, 2, "purple"));

}

}



Solution :What’s The Point?


The main method creates and prints a ColorPoint instance. The println method invokes the toString method of the ColorPoint instance, which is defined in Point. The toString method simply returns the value of the name field, which is initialized in the Point constructor by calling the makeName method. For a Point instance, the makeName method returns a string of the form [x,y]. For a ColorPoint instance, makeName is overridden to return a string of the form [x,y]:color. In this case, x is 4, y is 2, and the color is purple, so the program prints [4,2]:purple, right? No. If you ran the program, you found that it prints [4,2]:null. What is the matter with the program?



The program suffers from a problem with the order of instance initialization. To understand the problem, we will trace the program execution in detail. Here is an annotated program listing to guide us:




class Point {

protected final int x, y;

private final String name;



Point(int x, int y) {

this.x = x;

this.y = y;

name = makeName(); // 3. Invoke subclass method

}



protected String makeName() {

return "[" + x + "," + y + "]";

}



public final String toString() {

return name;

}

}



public class ColorPoint extends Point {

private final String color;



ColorPoint(int x, int y, String color) {

super(x, y); // 2. Chain to Point constructor

this.color = color; // 5. Initialize blank final-Too late

}





protected String makeName() {

// 4. Executes before subclass constructor body!

return super.makeName() + ":" + color;

}



public static void main(String[] args) {

// 1. Invoke subclass constructor

System.out.println(new ColorPoint(4, 2, "purple"));

}

}



In the explanation that follows, the numbers in parentheses refer to the numbers in the comments in the annotated listing. First, the program creates a ColorPoint instance by invoking the ColorPoint constructor (1). This constructor starts by chaining to the superclass constructor, as all constructors do (2). The superclass constructor assigns 4 to the x field of the object under construction and 2 to its y field. Then the constructor invokes makeName, which is overridden by the subclass (3).



The makeName method in ColorPoint (4) executes before the body of the ColorPoint constructor, and therein lies the heart of the problem. The makeName method first invokes super.makeName, which returns [4,2] as expected. Then the method appends the string ":" and the value of the color field, converted to a string. But what is the value of the color field at this point? It has yet to be initialized, so it still contains its default value of null. Therefore, the makeName method returns the string "[4,2]:null". The superclass constructor assigns this value to the name field (3) and returns control to the subclass constructor.



The subclass constructor then assigns the value "purple" to the color field (5), but it is too late. The color field has already been used to initialize the name field in the superclass to an incorrect value. The subclass constructor returns, and the newly created ColorPoint instance is passed to the println method, which duly invokes its toString method. This method returns the contents of its name field, "[4,2]:null", so that is what the program prints.



This puzzle illustrates that it is possible to observe the value of a final instance field before its value has been assigned, when it still contains the default value for its type. In a sense, this puzzle is the instance analog of (Larger than life), which observed the value of a final static field before its value had been assigned. In both cases, the puzzle resulted from a circularity in initialization. In Larger than life, it was class initialization; in this puzzle, it is instance initialization. Both cases have the potential for enormous confusion. There is one point where the analogy breaks down: Circular class initialization is a necessary evil, but circular instance initialization can and should always be avoided.



The problem arises whenever a constructor calls a method that has been overridden in its subclass. A method invoked in this way always runs before the instance has been initialized, when its declared fields still have their default values. To avoid this problem, never call overridable methods from constructors, either directly or indirectly . This prohibition extends to instance initializers and the bodies of the pseudoconstructors readObject and clone. (These methods are called pseudoconstructors because they create objects without invoking a constructor.)



You can fix the problem by initializing the field name lazily, when it is first used, rather than eagerly, when the Point instance is created. With this change, the program prints [4,2]:purple as expected:




class Point {

protected final int x, y;

private String name; // Lazily initialized



Point(int x, int y) {

this.x = x;

this.y = y;

// name initialization removed

}



protected String makeName() {

return "[" + x + "," + y + "]";

}



// Lazily computes and caches name on first use

public final synchronized String toString() {

if (name == null)

name = makeName();

return name;

}

}



Although lazy initialization fixes the problem, it is a bad idea to have one value class extend another, adding a field that affects equals comparisons. You can't provide value-based equals methods on both the superclass and subclass without violating the general contract for Object.equals or eliminating the possibility of meaningful comparisons between superclass and subclass instances .



The circular instance initialization problem is a can of worms for language designers. C++ addresses the problem by changing the type of the object from the superclass type to the subclass type during construction. With this solution, the original program in this puzzle would print [4,2]. We're not aware of any popular language that addresses this issue satisfactorily. Perhaps it is worth considering making circular instance initialization illegal by throwing an unchecked exception when a superclass constructor calls a subclass method.



To summarize, you must never call an overridable method from a constructor under any circumstances. The resulting circularities in instance initialization can be fatal. The solution to this problem is lazy initialization .