Re: mutate an object or create a new one?
toton wrote:
2) Only thing I like immutable object, [...]
I try to have immutable object as
much as possible. It makes a lots of thing simpler.
That's sensible.
Resetting an object is not free, neither memory allocation. But what is
the cost comparison for Java (in C++ resetting an object is cheap,
memory allocation in heap is costly. Thus STL do so much copy, but
little memory allocation, and still is very fast).
Ah, you are a C++ programmer. You will almost certainly find that your
intuitions about costs are wrong in the Java world.
That's for two important reasons: one is that in Java certain operations are
performed /much/ more often than in C++ (object allocation is a case in point),
and so they receive a great deal of attention from the JVM implementers. The
other reason is that Java implementations (at least on desktop machines and
bigger) tend to be extremely advanced (Sun's JVMs as about close to the
bleeding edge as you can get), and so the implementation techniques are less
than obvious, and the mapping from source code to eventual machine code may be
a lot more indirect than would normally be the case with a C++ program. The
effect of adaptive optimisation alone makes it hard both to reason about, and
to measure, performance (BTW, any micro-benchmark -- like the one in your first
post in this thread -- which does not take account of adaptive optimisation is
probably completely useless.)
Now, on desktop (and better) machines object allocation is /very/ fast (only a
very few instructions -- less than it takes to zero the memory for the newly
allocated object), and normally it would be a mistake to use object pools
(might even slow the program down, since the GC algorithms are designed and
tuned on the -- correct -- assumption that most objects don't survive for very
long at all). Whether that still applies in your target JVM (on the iPAQ) I
have no idea. But what you can be fairly sure of is that the target JVM's
memory handling has been very carefully designed around the hardware's balance
of CPU speed and memory size. To put it another way, its a fair bet that the
JVM can manage memory faster than you can do it yourself ;-)
3) I have a little more question. I want a few of my classes to evolve
over time (i.e they are mutable.) as all of the states are not
available initially. However if anyone wants it I need to send an
unmodifyable snapshot of it ( i.e constantify it & send). Again as Java
do not have const, I am looking for some inner class based
implementation. Anything specific known regarding that? (like a
modifier class, If someone gets access to modifier of a class he will
be able to modify its state, otherwise the class is immutable! ) .
I suggest that before you get stuck into complex code to try to replicate C++'s
pointer-to-const semantics, you should first get some practise with working
without it. This is (IMO) another case where intuitions trained on C++ are not
applicable in the Java world; and you may find that the cost/benefit equation
of "controlled mutability" favours a different balance in Java. Consider that
in C++ sticking "const" onto some declaration has minimally disruptive effect
on the source and/or overall design, and has zero cost at runtime. In Java
there is no equivalent of that mechanism, so controlled immutability (as
opposed to just creating completely immutable objects) would have a cost in
both design/code effort, and at runtime. The costs are higher, but the benefit
is at most the same and may actually be smaller (as a result of Java's
generally safer and less easy-to-break-accidentally semantics).
I.e. just don't bother (normally).
On the fairly rare occasions where you /do/ need to hand out data while
disallowing changes to it, you should consider at least three options:
1) Just hand out a copy (remember allocation is cheap in Java). This should
be your first choice since it is both simple and totally reliable.
2) Hand out a reference to the data, but in the form of a reference of a type
which doesn't include mutating operators. Oliver and Ingo have already
discussed this option. Note that there is not much to prevent the consumer
from misusing the reference by downcasting it back to the mutable type.
3) Hand out a helper object which itself has no mutating operations, and which
implements readonly operations by forwarding them to the "real" object. Thus
the consumer only ever has controlled access to the real object. Something
like:
public class MyStuff
{
private RealData m_realData;
public static class PublicData
{
private final RealData m_data;
PublicData(ReadData data) { m_data = data; }
public int getX() { return m_data.getX(); }
}
private static class RealData
{
....
int getX() { ... }
void setX(int x) { ... }
....
}
public PublicData
getData()
{
return new PublicData(m_realData);
}
}
There's nothing magical about the use of nested classes in the above. They
might make the code look prettier for this kind of application, but they don't
add anything semantically different from what you could do with "real"
(top-level) classes.
Do note that all these options add complexity and have a runtime cost (which
may not, in fact, be very great, but it won't be zero). Don't use these
techniques unless you have a better reason than just a habit carried over from
C++.
-- chris