Usea Collecting Parameter In Accessor Methods

A data point: I was browsing around Swing and I noticed

public Rectangle getBounds(Rectangle rv)

Store the bounds of this component into "return value" rv and return rv. If rv is null a new Rectangle is allocated. This version of getBounds() is useful if the caller wants to avoid allocating a new Rectangle object on the heap.

-- WilliamGrosso


How about this variation:

Point getPoint(Point p) {
if (p == null) {
 p = new Point();
}
p.x = myXvalue;
p.y = myYvalue;

return p; }
This lets you have the convenience of both worlds. You can pass "null" if you want a new Point to be created, or non-null if you want to reuse an existing Point.

I use this method a lot for returning 3D coordinates in my program.

class Vertex {
private double x, y, z;// Vertex coordinate

double[] getCoordinate(double[] c) { if (c == null) { c = new double[3]; } c[0] = x; c[1] = y; c[2] = z; return c; } }
Then I can do:
double[] c = null;

for (int i=0; i<numVertices; i++) { c = vertex[i].getCoordinate(c); // Do something with c }
Neat syntax and efficiency all at the same time....whaddya think?

FTB.


I think that you should use a mutable object instead of an array. -- PhilGoodwin


Ok, but if we can imagine for a moment that I've got a good reason for using arrays in my particular program, and also look at the example I gave for "Point" (a few lines above the array thing), what do you think of the idiom??

FTB.

I think that I'm torn. It seems to be convenient but it also seems to have more than one responsibility. I definitely think that the method name is confusing: Something like "vertex[i].copyCoordinateTo(c);" would be more readable (although perhaps too wordy). I also don't think that you'd be losing anything by requiring that the incoming reference not be null. At that point you'd have an effective way to circumvent Java's inability to manipulate objects by value, I think. The only other thing is to recognize that this is a performance optimization - probably not an everyday coding idiom. -- PhilGoodwin

It's a performance optimization, pure and simple, and as such is silly until proven otherwise. Just return a new Rectangle every time. An immutable one. Mutable value objects are the work of the devil. Don't dance with the devil until performance issues force you to. And then use 50's rules for dancing (not too close!).

I concur. In the HotSpot JVM, it takes merely a couple of pointer arithmetic operations to allocate an object. Furthermore, you don't create any more live objects that way, so there is no additional GC overhead. Why add the additional complication of mutable ValueObjects (ValueObjectsShouldBeImmutable), and the perhaps locking overhead when accessing those objects in a multithreaded program, just to save yourself a couple of additions each time.

Also note that some garbage collectors (namely those that are optimized for an almost-functional style of programming) place a higher cost on non-initializing mutation than on allocation. E.g., in a GC that implements generational collection and maintains a write barrier by relying on the operating system's dirty page mechanism, a single write into an "old" object might force the GC to rescan a whole page (4K on an x86) on the next minor GC.


"I also don't think that you'd be losing anything by requiring that the incoming reference not be null." - You lose the ability to write in a concise, functional style like:

window.setClientArea( model.getRectangle(NULL) );
Instead, you must write something like:
Rectangle r = new Rectangle();
model.getRectangle( r );
window.setClientArea( r );
which is three times as verbose, harder to read, more tightly coupled and generally evil. Incidentally, this idiom makes the implementing code more verbose too. Eg the getPoint() example would otherwise be:
Point getPoint() {
return new Point( myXValue, myYValue );
}
which is again 1/3rd the length.

Um, no. :p
window.setClientArea( model.getRectangle( new Rectangle() ) );
The implementing code may well be more complex, but I'd rather that complexity be there once and only once than at every call site. If the implementing code is common it can be factored; but the logical place to refactor from multiple call sites is back to the implementing code.

Of course, this is not to say that it's always necessary, but I've consistently found myself refactoring many pieces of library code into this form. It's the most straightforward way of making it configurable for performance, flexibility, etc., when the code is common enough to be used in widely varying manners in the same object[s].

-- WilliamUnderwood


This version of getBounds() is useful if the caller wants to avoid allocating a new Rectangle object on the heap.

I'll put this on the list of things I'm glad I don't need to worry about on a daily basis.


EditText of this page (last edited May 21, 2005) or FindPage with title or text search