 |
Arrows in the Back
Posted by cayhorstmann on January 07, 2007 at 03:25 PM | Comments (21)
I had blogged
on property boilerplate and the work of my graduate student Alexandre
Alves in the summer, but I didn't get much reaction then. But recently,
there has been a flurry of blogs on native property syntax. Let's try this
again.
Why Native Properties?
Many programmers are sick and
tired of boring, repetitive boilerplate code for JavaBeans properties.
Here is a simple code example from the JBoss EJB3
tutorial.
@Entity
public class LineItem implements java.io.Serializable
{
private int id;
private double subtotal;
private int quantity;
private String product;
private Order order;
@Id @GeneratedValue(strategy=GenerationType.AUTO)
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public double getSubtotal()
{
return subtotal;
}
public void setSubtotal(double subtotal)
{
this.subtotal = subtotal;
}
public int getQuantity()
{
return quantity;
}
public void setQuantity(int quantity)
{
this.quantity = quantity;
}
public String getProduct()
{
return product;
}
public void setProduct(String product)
{
this.product = product;
}
@ManyToOne
@JoinColumn(name = "order_id")
public Order getOrder()
{
return order;
}
public void setOrder(Order order)
{
this.order = order;
}
}
64 lines. Boring, repetitive lines.
Alex's implementation of native properties crunched it down to 12
lines. (Don't get hung up on the @Property syntax--see below...)
@Entity
public class LineItem implements java.io.Serializable
{
@Id @GeneratedValue(strategy=GenerationType.AUTO)
@Property private int id;
@Property private double subtotal;
@Property private int quantity;
@Property private String product;
@ManyToOne
@JoinColumn(name = "order_id")
@Property private Order order;@
}
I thought this would be a total
no-brainer. Wouldn't you rather read 12 lines of code than 64 lines?
Well, apparently not everyone. There are many emotional reactions
floating around in the blogosphere.
"What's the Big Deal, Dude? My IDE Writes
Getters/Setters for Me!"
Does your IDE also read them to you, dude?
Seriously, maybe an IDE could do intelligent code folding and show you
a one-line property when it sees six lines of getter/setter pairs in the
code. That sounds rather fragile, but it would be better than nothing.
"The Arrows are So Ugly! No, they are Silly!"
Where do the arrows come in, you
ask. There are several proposals for a property access operator.
- Danny Coward floated
the arrow operator, such as item->quantity = 10;
- Alex used the .@ operator, such as item.@quantity =
10;
- Many people say "Let's just use the dot--it works for C#"
- Some people say "Let's not have any property access operator. Just
call the getters and setters."
The arrow got people excited. Everyone loves to hate the arrow
(see here,
here,
and here).
I don't know why--it is just an operator. Maybe .@ is prettier?
Surely, there is some token that can be parsed unambiguously and that
doesn't cause emotional waves.
Using just the dot is unfortunately a minefield. You'd have to look
closely what item.quantity means. Is there an accessible field
quantity? Is there a quantity property? Who wins if both
are present? Or is that illegal? I am sure that one can cook up a set of
rules, but is it worth it? Why are people so attached to the dot? For
example, Peter von der Ahé writes: "It
has to be '.' (dot). Anything else would look silly."
Having no operator at all might work. Look at the EJB3 example--most of
the getters and setters invocations are done through reflection anyway.
"Getters and Setters are Evil!"
There is a lot
of sanctimonious handwringing on how getters and setters break
encapsulation. Yup. They do. People should never write code like that
LineItem class. But guess what...they do.
Why do good people write such evil code? Many tools require bean
properties. If you write EJB3 entities, JSF components, client-side
components, etc. etc, you end up writing lots and lots of getters and
setters.
"Let's Break Free from Beans!"
One of programmers at Borland
once told me how, around 1996, their team showed the Delphi GUI builder to
the Java group. Their eyes popped out. They had never seen a visual GUI
builder. They had never understood why people preferred Visual Basic over
AWT or Motif--after all, everyone knows that Basic is icky. But once they
realized that a VB programmer can do in a day what takes weeks in Motif,
they too wanted a GUI builder. A GUI builder shows a property sheet. Java
needed properties. That's how the JavaBeans spec was born--it fakes
properties as getter/setter method pairs. [I don't know if this story is
actually true--I'd love to hear from the Java veterans.]
Of course, faking properties as getter/setter method pairs has been an
ugly mess.
It is tempting to start with a clean slate. My guess, though, is, that
we will get some integration of native properties with
java.beans.Introspector, for compatibility with legacy code.
"Don't Break My Code with a New Keyword!"
Alex used the @Property annotation in his prototype. Sure, a
property keyword would have been nicer, but that breaks the
gabazillion lines of code that use property as a name. Then
again, annotations are not supposed to change the semantics of the class
to which they are applied, but Alex' @Property synthesizes
getters and setters. What can be done?
- Abuse a rarely used keyword, such as static,
super, or goto.
- Use a token. That's what happened in Java 5. for (element :
collection) instead of for (element in collection).
I think the token approach will probably win out. I hate to give an
example, because people will say "that's so ugly". But just to show that
it can be done...you can put an @ after the type. For example,
here is a quantity property.
public int @ quantity;
I know it's ugly. Don't tell me "native properties are a bad idea
because this syntax is ugly". Someone will come up with something
acceptable. Or we'll all get used to something ugly, just like we got used
to the colon in the for loop.
"Native Properties are Boring. Let's Talk About Closures
Instead!"
Or reified generic types. Or XML
syntax. I am glad that people worry about solving (or creating) tomorrow's
problems, but property boilerplate is a problem that we have today.
Let's Go Beyond the Emotions
Before vilifying a proposal because of unsightly syntax, let's
summarize what one wants in native properties.
- The common case--a private field and public getter/setter
pair--should require minimal boilerplate.
- It should be easy to supply getters and/or setters that do some
other work.
- It should be easy to specify read-only or write-only properties.
- Javadoc should document properties.
- There should be reflective access to properties.
- Properties need to integrate with annotations.
Here are some issues that have been raised.
- Should getters and setters of native properties be regular methods?
- Should native properties be compatible with JavaBeans properties?
- Should there be support for
bound and vetoable properties?
- Should properties have other than public visibility?
The issue that has gotten the most press, namely what operator, if any,
to use for property access, seems the least important one.
Bookmark blog post: del.icio.us Digg DZone Furl Reddit
Comments
Comments are listed in date ascending order (oldest first)
-
Unfortunately the arrow syntax debate has got confused with the syntax sugar generate properties debate. These are two completely separate language changes. (The former is a highly debatable language change, the latter is a no brainer)
The property generation language change has the potential to completely change developers interaction with frameworks, and greatly increase the robustness and clarity of out code. I discuss these property objects on my blog.
So, to your points - I agree with your first 4 points, but believe strongly that reflective access to properties misses a huge opportunity. I prefer a keyword for property generation, Remi has already shown that a context sensitive keyword can work here. An annotation would be a misuse. And yes, generated get/set methods should act just like any other method.
Posted by: scolebourne on January 07, 2007 at 04:59 PM
-
It just raises so many questions. With a @Property, someone might ask whats the point? if your getters and setters are that trivial, why not just make the fields public? and we'd say, it allows you change the behaviour in the future, and allows you to override them in the subclass...
So, how would I validate these properties? (eg, null checks, range checks etc). what about notifying PropertyChangeListeners? and how do I override them in a subclass? what about declaring the exceptions it throws when setting, but getting doesnt throw any? how do you do read/write only?
I like getters and setters because they're clear and concise. its obviously exactly what they do and how they behave. its just natural.
i just dont think that any of these new proposals arent going to improve the quality of our software or get our software written any faster. its just complicating something thats already trivial.
Posted by: benloud on January 07, 2007 at 05:18 PM
-
I agree, there's nothing gained with an @Property annotation-- we need something actually in the semantics themselves which allows the inclusion of proper get/set semantics. Using a reserved word like 'property' will have no more of an affect than enum, and people will welcome it just as they did with Enums. Secondly a property is not the same as a member variable, so I think many people's complaints on OO/encapsulation are an illegitimate argument against properties. Finally, I'm in the C# syntax camp-- if they are adding closures, I don't see why adding property syntax would be any different, putting it as a close relation to the method type.
Posted by: jhook on January 07, 2007 at 09:52 PM
-
The whole point of getters and setters over direct access to fields is to allow validation and computed properties. C#-style syntax is clear.
Getter/Setter syntax also lets you encapsulate property change events, binding, and vetos. I see lots of clever workarounds to put this into annotations and the like, but hey, method bodies are also a nice place to put code, and it's very flexible...
IDEs generate boilerplate for you. IntelliJ also lets you have a bean view of JavaBean-style properties, as I imagine most other IDEs do.
- Chris
Posted by: chris_e_brown on January 08, 2007 at 12:26 AM
-
There's an interesting parallel discussion here: Property Support in Java, the Java Way (on JavaLobby).
- Chris
Posted by: chris_e_brown on January 08, 2007 at 12:32 AM
-
Cay, property can be declared using the keyword 'property' without breaking all existing codes.
I've blogged on such keywords.
Futhermore, i've recently patched the java compiler to provide properties that :
useq a keyword 'property'
auto-generates getter and setter
allows to use dot to access to a property.
All these stuffs are provided without breaking compatibility.
Rémi
Posted by: forax on January 08, 2007 at 12:43 AM
-
an idea:
every private member of a class receive getters and setters by default.. unless it is annotated to not have it.
like:
private int i; // this will have get/set
@hidden // any annotation name..
private int j; // this will not...
why not ?
we get familiarized with the programing without getter/setter by default - why not with getter/setter by default ?
:)) all this simplification ideas impact in a complex task of modifing the beliefs of a huge community..
Posted by: felipegaucho on January 08, 2007 at 01:21 AM
-
Actually, options are endless if syntax will allow "contextual" keywords, i.e. in one place this is a keyword, in other it's a variable name. Same way as get/set is treated in JavaScript.
Say, "property" may goes between visibility modifier (if any) and type of field... oops property:
public property String name; // public property
property String otherName; // package-visible property
String yetAnotherName; // package-visible field
public String nameAgain; // public field
This does not break any existing code at all and readable in English. Though, it's a bit verbose when it comes to overriding default getter/setter. Probably some variation of C# or AS3 syntax is better:
public String name
get { return default; }
set(v/* type expression here is redundant */) {
validate(v);
default = v;
}
;
public int trivialRWProperty get set; // read-write property
public Date justROProperty get { return new Date(); }; // read-only property
public int x get; // compile-time error (?)
Here we may exploit the fact that "default" already reserved and left task of generating field name to compiler. Depending on usage of "default" in code compiler decides whether or not corresponding auto-generated field is necessary at all.
Obviously, exceptions may be added to get(rare)/set(typically) accessors/mutators.
As of closures in Java, I firmly believe it's to early to get this functionality. First, Java need type inference. Without this any attempts to create closures will result to ugly verbose syntax. Even now I hate this:
//in some method
HashMap< String, WeakReference< MyBusinessObject > > refMap = new HashMap< String, WeakReference< MyBusinessObject > >;
Why not allow this (Groovy-like):
def refMap = new HashMap< String, WeakReference< MyBusinessObject > >;
Second move should be introducing function types and closures over class/instance methods. And only afterwards it's possible to think about "real" closures.
Valery
Posted by: vsilaev on January 08, 2007 at 03:28 AM
-
valery, your syntax def var = is ambiguous
def can be a type.
but three other syntaxes was proposed for that purpose
see my blog
and the blog of neal gafter
Rémi
Posted by: forax on January 08, 2007 at 05:19 AM
-
If there is a special syntax to access properties, a client needs to know if a property (general sense) is implemented as a property (proposed Java facility). Isn't that an implementation detail a client doesn't want to know?
Posted by: hoogenm on January 08, 2007 at 06:10 AM
-
All this talk about the existing bean pattern being an "ugly mess" is something I don't understand. I haven't ever encountered any issues with it.
Another thing that all of these proposals seem to miss is that proper support for properties should handle PropertyChangeSupport. With out that "native" properties will be of very little value anyway.
Native properties aren't a bad idea because the "syntax is ugly", they are a bad idea because there is very little gain over the existing solutions. Yes my IDE writes getters and setters for me, NO it doesn't read them for me, but that doesn't matter because when I see getX() or setX(y) in the code it doesn't take extra effort to understand that code. I don't need to look at the actual getter and setter methods, everyone knows what they are supposed to do.. and of course the advantage is that those methods ARE there for me to look at if I want to see them. They are there to modify and tweak as needed as well.
This smells so much of a solution looking for a problem.
Posted by: swpalmer on January 08, 2007 at 06:35 AM
-
"Don't Break My Code with a New Keyword!"
I'm really tired of hearing about how new keywords will break old code. Maybe it will be a problem for your code base, maybe not. For us when we moved to JDK5 we had oh maybe 5 or 6 instances of variables named enum. As I investigate using the nifty new JDK6 I have literally hundreds of conflicts because Sun decided to include SwingWorker. We unfortunately depend on an older version of SwingWorker and so now I have to change the name of the class, and change all the import statements blah, blah, blah.
My point is, lots of things break code. Lets concentrate on building the most straight forward and easy to code semantics when extending the language. If it breaks the language just a little thats ok, a little is better in the long term then confusing hacks to accommodate older code.
Posted by: aberrant on January 08, 2007 at 06:58 AM
-
Bound property support is critical. If a solution cannot be designed with that in mind, then I say hold off.
I use properties in .Net, but I don't think too much of them. There's little or no savings in terms of lines-of-code, but API's are more complicated because sometimes you end up using a Get or Set method anyway, in addition to properties, which means in the docs now you have to look at 2 different reference sections. Even Microsoft has done this.
But good discussion, keep it up.
I wish there were a way to inject generated source code into the original .java file based on an annotation processor, and have it marked as generated code. Then we can all "have it our own way", IDE's can understand it without needing to be enhanced for a new notation.
Posted by: jsando on January 08, 2007 at 08:25 AM
-
[I don't know if this story is actually true--I'd love to hear from the Java veterans.]
I don't believe that's true. I am sure that Borland showed Delphi to someone at Sun whose eyes bugged out (probably from Marketing, considering how poorly we do it :-). Howeve, the JavaBeans lead, Graham Hamiliton, knew all about VB and visual editors long before then.
Posted by: tball on January 08, 2007 at 09:03 AM
-
For me the most common case for a property is in interfaces. As many programs work with data, passing data items back and forward is not so uncommon, a definition in an interface that says that there is a property "time" should say that I can set and get the "time" to/from it.
This is also why I don't like the notion of overriding get/set; these methods should simply emit an event and never alter the value (this is also the recommendation in C#) - at most save copy should be allowed.
Virtual properties (or "abstract" in Rémi's patch) pose the problem for the implementation to write a proper get/set pair: (p.set(x);p.get().equals(x))
If these conditions are not satisfied the usablitity of properties goes down as again the behavior on get/set has to be specified separately
Posted by: csar on January 08, 2007 at 11:59 AM
-
I think the discussion here is to superficial.
The case is not only to avoid the setter and getter methods with some kind of new syntax. You also have to provide a solution to change the behaviour of the property.
I think nothing is gained if you allow short, trivial code and make real world code more complex. Somebody used the EJB example, would you really implement a setter without range check? Yes, I know there are some annotations for range checks, but what kind of error they produce and how to handle it? And how to check that my property takes lower case characters only? Or you might want to limit the date to be larger than some other date...
The new solution has to provide short trivial properties and a simple and intuitive solution to change the behaviour of the property. The bean specification also provides property change support. The new solution should also provide a clean solution for the property change support.
If you want to change something, read the Bean specification first to really know what you want to change.
I hope that the discussion starts to address the whole complexity of the issue versus my syntax looks better than yours.
Posted by: pinus on January 08, 2007 at 12:19 PM
-
@pinus, there is no clean solution. There are lot of good solutions.
see Why don't provide property change support ?
Rémi
Posted by: forax on January 08, 2007 at 02:26 PM
-
Someone posted a comment including the take that "Property access just is really kinda ho hum" and this doesn't warrant a keyword. I found this very rational.
I posted a reply to this comment on the long discussion posted by Mikael Grev on JavaLobby. My comment is here:
http://www.javalobby.org/java/forums/m92123549.html#92123549
Posted by: steevcoco on January 08, 2007 at 03:51 PM
-
One thing I haven't really seen anyone debate anywhere that has saved my butt repeatedly are break points. Maybe I'm the only one who ever does this but when I'm trying to figure out how a variable is getting set in an object I'll very often put a break point in the setXYZ( ... ) method. It gets called a couple times, I check some stuff on the stack... AHA thats why its being called.
This has saved me repeatedly. Maybe I'm missing something but if we move code to this property notation, where will I put my break point? At the declaration? How will I be able to indicate I want to break just at the assignments and not the references?
Posted by: alekd on January 09, 2007 at 09:41 AM
-
alekd,
If we have code generation with annotations there's no problem to set the breakpoint on the setter or getter since the code is in the .class files. The IDEs needs to be updated a bit but they need that in any case.
Cheers,
Mikael Grev
Posted by: mgrev on January 09, 2007 at 01:59 PM
-
@alekd, I don't know if other IDEs have this feature, but if you use Eclipse, you can set a "write-only watchpoint" on the variable
Posted by: dserodio on January 10, 2007 at 05:10 AM
|