There’s an awful lot of sound and fury right now about adding syntax support for properties to Java 7. However, all the proposals are vastly too complex for what little benefit they offer. They need new keywords, operators, rules, and best practices. Could we have done better? Yes. Can we still do better? Maybe. Let’s find out.

The proper design of properties was invented in Eiffel over a decade ago, (or possibly some other language, but Eiffel is where I first saw it) and it’s really simple and obvious. All you need are public fields.

Oh my god! Public fields! The ultimate evil of object oriented programming that will bring about chaos, catastrophe, and the heat death of the universe! He can’t be possibly be serious, can he? Well, yes I can, because public fields don’t have to be bad.



Why Public Fields Are Bad

First, you have to understand the real problems with public fields. There are at least two. First you can’t change the implementation without breaking all client code. For example, suppose you have a Point class like this one:

public class Point { public double x; public double y; }

Now suppose later you discover that the points are occupying quite a lot of memory, and you don’t really need the extra precision of a double, so you’d rather use floats instead. You can’t. You’re stuck with doubles because that’s part of the interface. But suppose instead you had added an additional layer of indirection with getter and setter methods like so:

public class Point { private double x; private double y; public double getX() { return this.x; } public double getY() { return this.y; } public void setY(double y) { this.y = y; } public void setX(double x) { this.x = x; } }

Then you can easily change the private implementation while keeping the public interface the same, like so:

public class Point { private float x; private float y; public double getX() { return this.x; } public void setX(double x) { this.x = (float) x; } public double getY() { return this.y; } public void setY(double y) { this.y = (float) y; } }

The second, even more important problem with public fields is that you can’t check constraints. For example, suppose you have the very reasonable constraint that the x and y fields of a point can’t be NaN or Inf. If the fields are public there’s nothing to prevent anyone from doing this:

p.x = 7.5/0.0;

However if the fields are private the constructors and setter methods can enforce any such constraints, like so:

public void setY(double y) { if (Double.isInfinite(y)) { throw new IllegalArgumentException("Infinite magnitude"); } else if (Double.isNaN(y)) { throw new IllegalArgumentException("Not a number"); } this.y = y; }

Using setter and getter methods instead of public fields enables you to both change the internal implementation without breaking client code and to check constraints.

What Java Should Have Done About Public Fields

Can we add this ability to public fields? Yes. We simply have the compiler recognize that if there’s a setter, then p.x = 5 is really just a call to p.setX(5). I.e. the setter method overrides the assignment operator for fields. Similarly, if there’s a getter method double foo = p.y is just a shorthand for double foo = p.getY() . If there isn’t a setter or getter, then these statements read and write the field directly.

Suppose you want a read-only or write-only property? Just add a private getter or setter method like so:

private void setY(double y) { this.y = (float) y; }

Indeed this is more flexible than the current proposals because it would allow you to do things like create a property that is read-only to the general public but writable by subclasses:

public double getY() { return this.y; } protected void setY(double y) { this.y = (float) y; }

Notice that this technique requires no new keywords, syntax, or operators. Can we do this? Sadly no; I don’t think we can. The ship has sailed. This would break existing badly designed code that uses both public fields and a getter or setter. I don’t think there’s a lot of code like that out there, but there is some. The most prominent example is java.awt.Point. Not coincidentally, that’s also the poster child for the campaign to eliminate public fields.

Can we get close enough to this ideal that it’s worth doing? Maybe.

What Java Can Still Do With Public Fields

The ground rules are:

We have to introduce as little syntax as possible, ideally none, but just enough that we don’t change the meaning of any existing code. We don’t want to have to write getters and setters for the simple cases. We want the compiler to autogenerate these, but we do want to be able to provide our own if necessary. We want client code to be able to follow the standard Java naming conventions we all know. That is foo = p.getX() and p.setX(2.3) should work. We want client code to be able to follow the standard Java naming conventions we all know. That is foo = p.x and p.x = 2.3 should also work, and do the same thing.

I see two possible solutions.

A New Keyword

The first possible solution is to add a single property keyword to a field declaration like so:

public class Point { property double x; property double y; }

property would be an access specifier and fits in the grammar right where private, public, and protected do now.

This tells the compiler to autogenerate getters and setters for the field, but only if there are no such methods present already. (This is like how javac handles the default constructor now.) Furthermore, it indicates that calls that appear to be direct public field accesses should be dispatched to the getter and setter methods instead.

The downside to this approach is that we could only use the p.x syntax for new classes. We couldn’t use it for existing classes that do have getter and setter methods that follow the JavaBeans naming conventions but have not been retrofitted with properties.

New methods

The second possibility is to add methods whose sole purpose is to override access to fields. These could begin with $ character, which is currently allowed in method names by the Java VM, but not allowed by the compiler. (Some byte code obfuscators use this trick to prevent decompilation.) This would avoid any accidental conflicts with old code. For example,

public class Point { public double x; public double y; public double $x() { return this.x; } public void $x(double x) { this.x = (float) x; } public double $y() { return this.y; } public void $y(double y) { this.y = (float) y; } }

However, the compiler would only use these methods for field access if they were present. Otherwise it would read and write the fields directly.

The problem is that I don’t see how to easily fit the existing setFoo and getFoo methods into this scheme. These methods could certainly still be present, but there’s no way to autogenerate them. This improves new classes, but does little for use of existing bean classes.

Neither solution seems clean enough to make me sure it ‘s worth the cost, but these are the best I’ve come up with; and I think they’re better than the other proposals I’ve seen. They involve fewer changes to the language, and are more powerful, especially in that they allow greater programmer control over access to properties.

In the end, I think the only reasonable solution is a clean break. Go to a full-on Eiffel solution where methods with the same name as a field override the access to the field:

public class Point { private float x; private float y; public double x() { return this.x; } public double y() { return this.y; } public void y(double y) { this.y = (float) y; } public void y(double x) { this.x = (float) x; } }

Anything else is just a half measure that will cause more confusion than it solves. Sometimes to fix a broken bone that’s set wrong, you have to break it again first. In many ways, Java has set wrong. Property access is just one example. Sooner or later we’re going to have to admit that it’s time to start over and create a new Java 3 that makes a clean break with the past and is no longer limited by backwards compatibility. Otherwise, Java is just going to become a confusing mess of compromises that will be less and less accessible to anyone who didn’t grow up with the language.