Proper Properties
In the great Java property debate, a lot of rather exotic ideas have been put forward. Using a new ‘property’ keyword; using an arrow (->) or at-sign (.@) or even a pound-sign to include null-safe access.[1] Me, I don’t get it. Sure, getters and setters make for lines and lines of repetitive code and they’re annoying to browse through. But at least they don’t get in the way when I’m coding, like the lack of closures does–to name just one thing.
So my contribution to the debate will be a conservative one, even if it is inspired by Ruby. It will not conflict with existing code or syntax. It will not use new keywords or exotic ascii characters. It will not use annotations to generate code (but it will use annotations). It will not include null-safe access. It will not get rid of getters and setters. So what will it do?
In a Ruby class, fields can be specified using one of three methods, like this:
class Person attr_accessor :lastname attr_reader :firstname attr_writer :age end
After instantiating an object of this class, we can access the properties using just their names, like this:
person = Person.new person.lastname = "Doe" print person.firstname person.age = 44
Even though it looks as if you’re directly using the fields, these are actually method calls. That’s right, Ruby allows you to skip parentheses on method calls, so you’re really doing this:
person.lastname=("Doe") print person.firstname()
So where did these methods come from? They’re dynamically inserted into the class definition at runtime by the attr_accessor, attr_reader and attr_writer methods. Internally, the class can reference its fields as self.lastname
. That’s how Ruby discriminates between field and corresponding method. Need a custom getter or setter? You can always define the generated method explicitly, in which case it will not be generated for you.
My Properties Proposal For Java
So how can all this revolutionary stuff lead to a conservative proposal for Java properties? As Java is not dynamic, it cannot insert methods at runtime. So how about we let the compiler insert them at compile time, in the compiled class? All you have to do yourself is declare the field–and by default, the compiler will generate a getter and setter method. How would that work out?
It will not conflict with existing code. If you already have getters and setters in your class, they will not be generated for you. I would suggest adding a compiler option to enable the generation. If you do not use the option, you do not get the generated methods. So existing code will compile and result in the same classes as they did before. Only if you do use the option, you get the new behaviour.
It will use annotations–but not to generate code. Because the code will be generated anyway. But you could use annotations to parameterize the generation. We could have an annotation to generate just a getter or just a setter. There could also be an annotation to toggle special behaviour in the methods (fire an event?). And how about an class-level annotation to turn generation on or off for all fields in that class?
It will not use new keywords or exotic ascii characters. It will not get rid of getters and setters. Getters and setters will still be there–you just won’t have to write them yourself anymore, or have your IDE insert them, or have to browse through them. Sure, you don’t get to use that cool new arrow sign. All the more reason to support the closure proposal, which has an even cooler fat arrow sign.
It will not include null-safe access. Of course it won’t. What did you think, that the compiler would do everything for you?
And now for the obligatory fantasy code sample:
public class Person { // Will generate getter and setter: private String lastname; // Will generate getter: @FieldReader protected String firstname; // Will generate setter: @FieldWriter public Integer age; public static void main(String args[]) { Person p = new Person(); // Use the generated methods: p.setLastname("Doe"); p.getLastname(); p.getFirstname(); p.setAge(44); } } @FieldAccess(access=NO_ACCESS) public class Address { // Will not generate anything because of class-level annotation: private String street; }
29-01-07 UPDATE: I have put this proposal on javap.info.
[1] Am I the only one who dislikes this language-design-by-ascii?
— “We need a new language feature!”
— “O don’t worry, we’ve got all these weird-looking characters that we can still use. How about the €-sign? It looks like an ‘e’, maybe we can use it to check if a collection is empty?”
2007-01-23. 6 responses.
Hi Danny,
Spot on! Actually, I was thinking along the same lines already. Guess its kind of obvious 🙂
Just a small thing: having a private member get a setter/getter by default seems a bit dangerous because it makes existing code non portable. A big no-no for Sun. A third member annotation, and/or a class annotation could alleviate this easily.
Erik.
This is way too obvious! You are hurting the Java community! FieldReader, FieldWriter and FieldAccess are probably already claimed by a annotation squatter deep down in the labs of Sun. Or.. “annotations should not be used like this” and some lengthy discussion about compile time annotations being evil. 😉
@Erik: it’s so obvious I can’t imagine I’m the first to think of it…
My idea is that you would have to explicitly set a command line compiler option to enable method generation. So if you don’t set that option, nothing will be generated. So your existing code base would compile as is, without any side effects.
Having to set command line options just makes using Java harder. You’d have to have separate compiles for separate files (assuming two files in the same codebase want different options).
I’d much prefer doing this in the language. A ‘property’ keyword would be fine, and would only need to be a contextual keyword, i.e., in existing code, ‘property’ is already not allowed in the position it would be placed. In this way, no existing code is broken, and there’s no need for compile options.
Also, one of the awkward things about properties as they stand is the syntax for access; there’s nothing wrong with using a dot for property access instead of get/set methods.
@Ricky: okay, have it your way then: we make the switch work the other way around. So the compiler would by default generate accessor methods. Only if you use the switch, it won’t generate them. If individual files need non-default behaviour, use the class-level annotation (instead of using different compiler switches for those files). This is hardly a first for Java; see assertions.
Still no need for extra keywords or a confusing dot syntax.
Okay, its here. Someone has really done it:
https://bean-properties.dev.java.net/