Re: mutate an object or create a new one?
Chris Uppal wrote:
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.
Yes, I "see" Java memory allocations are much faster than C++ new
allocation (dynamic one). Java dynamic allocation almost competes with
C++ stack based (static) allocation!
Maybe someday Java will have an @valueType attribute to "help" memory
allocation for non-polymorphic objects (final objects), and the
collection will "hold" the value type objects! Who knows!
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.)
Heard sun is opening up its C++ sourcecode for JIT , eager to look at
the "bleeding edge" techniques.
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 ;-)
That always one programmer wants! But a human never wants a machine to
overperform him! what a irony!
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).
It is again like, I want an immutable class, but the class is big! How
to set all of the fields within constructor? It will be a huge list.
I have a Document class, which has name, address , and many other
fields. Now this class can load its fields from different types of
files, some are XML based, some simply name value pair. Now, the
Document need not to know the parsing logic, it is separated. A parser
for each type parses the file, and sets the field in the Document. and
when done, Document is ready, an immutable class. No more modification
is allowed. To make it immutable I need to pass all of the parameters
to the Document ctor, which is a long list (say 20 fields). Other thing
I can have is setters, which makes it mutable.
I "feel" there must be a better way. Like I make Document an inner
class for an abstract class Parser (or an interface) which all of the
specific parsers implement! Thus all of the parsers can access the
Document fields and set them. But no setters, thus no one else can do
it. Not sure about the idea ( I am not sure about the inner classes ).
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++.
In the meantime writting a Java "preprocessor" which recognizes const
keyword and do check! However no runtime check. In progress ! Will add
a good skill to my compiler knowledge! Not something serious, Just for
fun! The Java project is also my personal one only, as a hobby.
Thanks all for the long discussion and suggestions and advices!.
-- chris