Programming

my faceChris Foley is a computer programming enthusiast. He loves exploring new programming languages and crafting nice solutions. He lives in Glasgow, Scotland and works as a software developer.

Quirky Hello World!

I came across something quite interesting while I was coding today. Before I explain further, take a look at the following short Java program. It outputs two lines of text. Each line could be one of the following:

Write down what you think each line will be, then scroll down for the answer. Don't cheat now! Write down what you think the output will be first.

public class QuirkyHelloWorld {
	
	private  String message = "No message";
	
	public static void main(String [] args) {
		QuirkyHelloWorld a = new QuirkyHelloWorld();
		a.implementationA();
		QuirkyHelloWorld b = new QuirkyHelloWorld();
		b.implementationB();
	}
	
	public void implementationA() {
		display(message, prepare());
	}
	
	public void implementationB() {
		boolean reallyDisplay = prepare();
		display(message, reallyDisplay);
	}
	
	private boolean prepare() {
		message = "Hello World!";
		return true;
	}
	
	private void display(String greeting, boolean reallyDisplay) {
		if (reallyDisplay) {
			System.out.println(greeting);
		} else {
			System.out.println("Not today.");
		}
	}
	
}
The output is:
No message Hello World!

Before I explain, take a look at this modified version. It's the same program but this time I'm using a String Buffer instead of a String. Again, write down what you think the two lines are going to be.

(Hint: it's different from last time)

public class StringBufferHelloWorld {
	
	private StringBuffer message = new StringBuffer("No message");
	
	public static void main(String [] args) {
		StringBufferHelloWorld a = new StringBufferHelloWorld();
		a.implementationA();
		StringBufferHelloWorld b = new StringBufferHelloWorld();
		b.implementationB();
	}
	
	public void implementationA() {
		display(message, prepare());
	}
	
	public void implementationB() {
		boolean reallyDisplay = prepare();
		display(message, reallyDisplay);
	}
	
	private boolean prepare() {
		message.replace(0, 12, "Hello World!");
		return true;
	}
	
	private void display(StringBuffer greeting, boolean reallyDisplay) {
		if (reallyDisplay) {
			System.out.println(greeting);
		} else {
			System.out.println("Not today.");
		}
	}
	
}

This time we get:

Hello World! Hello World!

If you think the output to the first one was crazy, surely it's even crazier that these two programs give different outputs. Let's have a look at what's going on.

ImplementationB is more consistent so let's start with that. Prepare() is called, changing the message and returning true. These are passed to display(). Because the boolean is always true, we never display "Not today." so we get "Hello World" as intended.

What changes in implementationA? The key to this is remembering that an object variable is only a reference to an object, not the object itself. This time, the message is passed before prepare() is called. In the StringBuffer example, prepare() modifies the StringBuffer so message and greeting are referring to the same StringBuffer object. However, strings are immutable. In that example, we're creating a new String object ("Hello World!") and getting message to point to it. But by that time it's too late. Greeting is already pointing to "No message" and doesn't care about message or whatever object it's referencing.

The moral of this story is to always be clear of the difference between an object and a variable, and remember when calling methods that you pass the object, not the variable.

I hope you found this interesting. If you got the answers right be sure leave a comment exercising your bragging rights.

03 December 2008

Comments