Java Forum / General / November 2006
mutate an object or create a new one?
toton - 24 Oct 2006 09:08 GMT Hi, I have a typical situation for the main backbone of the program. In my program, lots of new objects gets created, added in the processing queue ,used and removed from the queue. Something like a air-traffic control system or moving average. The objects added to the queue, are by nature immutable, and that "may help" in a threaded environment (but not very much as the processing queues are seperate). However added immutability cause them to be use-and throw objects. While mutability cause them to be reused. I am trying to demonstrate the problem with a short example. While the original problem is much complex, but the underlying working principle is more or less same. public class TestProcess{ public static void main(String[] args){ Deque<ObjectTobeProcessed> queue = new ArrayDeque<ObjectTobeProcessed>(10); for(int i = 0; i <10; ++i){///pre existing objects. queue.addFirst(new ObjectTobeProcessed()); } long time1 = System.currentTimeMillis(); for(int i = 0; i <10000000; i++){ queue.removeLast();///remove the last one. queue.addFirst(new ObjectTobeProcessed());///add a new at the first. process(queue); } long time2 = System.currentTimeMillis(); System.out.println ("time "+(time2-time1)*0.001);
Deque<MutableObjectTobeProcessed> queue1 = new ArrayDeque<MutableObjectTobeProcessed>(10); for(int i = 0; i <10; ++i){///pre-existing objects. queue1.addFirst(new MutableObjectTobeProcessed()); } time1 = System.currentTimeMillis(); for(int i = 0; i <10000000; i++){ queue1.getLast().setValue(); process(queue); } time2 = System.currentTimeMillis(); System.out.println ("time "+(time2-time1)*0.001); } public static void process(Deque<ObjectTobeProcessed> queue){ double sum = 0; for(ObjectTobeProcessed o: queue ){ sum+= o.getValue(); } } } class ObjectTobeProcessed{ private double value; public ObjectTobeProcessed(){ value = Math.random(); } public double getValue(){ return value; } } class MutableObjectTobeProcessed{ private double value; public MutableObjectTobeProcessed(){ value = Math.random(); } public double getValue(){ return value; } public void setValue(){ value = Math.random(); } } Here two class creates some random number, while one allows to reset its state , the other do not. In the first case one number is removed from last, one created at first, and some process is called (here a moving average! ) . Here a large numver of objects created, used and thrown away. In the second case, it mutates the last object (which is supposed to be thrown away) to the new state. Here no object gets created and destroyed at all!. Here the queue sequence is not the same (that don not affect the moving average though), but that can be solved using a wrapped version of deque (with a modulo wrapping). There is a difference for first case and second case, and difference increases considerabily when the objects becomes complex and stores more than premitive types. In the actual problem, the existing size is not fixed (as 10 here) but nearly fixed within certain limit. And the objects come & go from the processing queue are not so small. And the system is supposed to be on for ever and process things as come and go away. The things I notice, 1) Both version has clear hotspot for processing. 2) only the second verson has hotspot for processing over same data. 3) For second version GC has very less job compared to first one. In actual case, the objects are characters (handwritten, not printed , thus they can not be formed from same set of objects). Mutating them means one can unknowingly or by mistake form a B from and A! Making them immutable means an easier and cleaner code, but error prone (as Java doesn't have a const , so I even can't constantify an mutable object when needed) Also I use Mysaifu JVM for PocketPC, which may not have as sophisticated GC as sun's one .Though still I hadn't tested the code there with a performance difference , I will do it in near future (my friend had take my iPAQ :( , sure he will return it by this weekend. Can anyone give a little more insight, and the best way to do such job? (The processing is pretty computational gemetry related and also has some signal processing aspect. in short instead of moving average, it is some sot of complex mathematical calculation comes into process). Any alternate / better way to do such job ? Something like I can have a mutable object but selectively constantify it when needed?
Thanks for any kinds of suggestion / advice
Chris Uppal - 24 Oct 2006 11:50 GMT > Also I use Mysaifu JVM for PocketPC, which may not have as > sophisticated GC as sun's one .Though still I hadn't tested the code [quoted text clipped - 4 lines] > some signal processing aspect. in short instead of moving average, it > is some sot of complex mathematical calculation comes into process). It sounds as if you are doing a lot of computation which isn't related to the creation/GCing of objects. As such the potential gains of avoiding GC (even in an environment where GC is slow) are going to be small at best. I.e it doesn't sound as if the extra complication would be worth it.
Remember, too, that recyling the objects is not free -- there are the extra costs involved in resetting the obejct's states, adding them to free lists (which would probably involve synchronised code), any additional runtime checks you have to ensure that you are not changing objects when you shouldnt and so on.
-- chris
toton - 24 Oct 2006 14:27 GMT > > Also I use Mysaifu JVM for PocketPC, which may not have as > > sophisticated GC as sun's one .Though still I hadn't tested the code [quoted text clipped - 15 lines] > you have to ensure that you are not changing objects when you shouldnt and so > on. 1) Actual case, there are one such queue per user. Say a new user starts writing, and a new deque is created, which are attached to each one's Session. And one's computation doesn't access or modify to other's data. So I don't do any synchronization there. 2) Only thing I like immutable object, as it protects from accidentally modifying data. Not that much for thread safety (as that comes relatively free to me, as I have separate Session for each user). However as Java doesn't have a const keyword ( which I use heavily in C++, and miss very much in Java) I try to have immutable object as much as possible. It makes a lots of thing simpler. Only this kind of cases I get little confused. It is a typical class of programs ! 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). 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! ) .
Thanks for help and suggestion.
> -- chris Ingo R. Homann - 24 Oct 2006 15:18 GMT Hi,
concerning your problem of recycling objects, my opinion is clear:
Do NOT recycle objects. It *may* speed up you app in some cases (while it may slow down your app in other cases). Write clean and readable code and choose the right data structures and algorithms. If your platform does not have enough resources to properly run your application, recycling objects will not help very much. In 99% there are more disadvantages than advantages.
To your other question ("const" (which I am missing as well) vs "mutability"):
I have not tested it in a productive environment, but an approach would by something like that:
class UnmodifiableInt { protected int i; public int getValue() { return i; } }
class ModifiableInt extends UnmodifiableInt { public void setValue(int i) { this.i=i; } }
Then, you can do the following:
class Foo {
void bar1(ModifiableInt i) { }
void bar2(UnmodifiableInt i) { }
void bar() { UnmodifiableInt ui = new UnmodifiableInt(); ModifiableInt i = new ModifiableInt(); bar1(ui); // compiler error bar1(i); bar2(ui); bar2(i); }
}
For "plain" objects (in contrast to "compound" objects) this should work easily.
Of course it is not "save" because if you have a reference of type UnmodifiableInt, it may point to an object of type ModifiableInt, so that you could do a cast. But on the other hand, casts are always somehow "unsafe"... (IIRC its the same with 'const' which you can "cast away")
On the other hand, even immutable Types like java.lang.String can be modified (using reflection).
Ciao, Ingo
Oliver Wong - 24 Oct 2006 19:26 GMT > Hi, > [quoted text clipped - 25 lines] > } > } I recommend having 3 classes, instead of 2 (or 2 classes, and 1 interface):
interface Int { public int getValue(); }
final class UnmodifiableInt implements Int { protected int i; public int getValue() { return i; } }
final class ModifiableInt implements Int { protected int i; public int getValue() { return i; } public void setValue(int i) { this.i=i; } }
The problem with the 2-class design is that it fails the IS-A test of inheritance: that is, it should not be the case than a ModifiableInt IS-A UnmodifiableInt. So you should not be able to use a ModifableInt anywhere an UnmodifiableInt is expected.
- Oliver
Ingo R. Homann - 25 Oct 2006 08:01 GMT Hi,
> The problem with the 2-class design is that it fails the IS-A test of > inheritance: that is, it should not be the case than a ModifiableInt IS-A > UnmodifiableInt. So you should not be able to use a ModifableInt anywhere an > UnmodifiableInt is expected. No, I think, the 2-class-design is better:
Consider you have a method that wants to indicate that it does not change the Parameter:
void foo(UnmodifiableInt i) {...}
Now, why should it be impossible to pass a ModifiableInt to that method?
And vice versa: Consider a method is returning an ModifiableInt:
ModifiableInt foo() {...}
Why should it be impossible to assign the returned value to a variable of type UnmodifiableInt to document that the variable will not be modified?
Ciao, Ingo
Chris Uppal - 25 Oct 2006 12:09 GMT > Why should it be impossible to assign the returned value to a variable > of type UnmodifiableInt to document that the variable will not be > modified? Because the user of the Unmodifiable should be able to rely on it not, in fact, being modified ?
To some extent this is a documentary issue rather than an OO design issue -- the question being whether and when the user of an object can assume that that object is immutable. For instance the class name "UnmodifiableXxx" strongly suggests immutability, the class name "ReadonlyXxxFacade" does not.
-- chris
Niklas Matthies - 25 Oct 2006 14:26 GMT >> Why should it be impossible to assign the returned value to a >> variable of type UnmodifiableInt to document that the variable will [quoted text clipped - 8 lines] > name "UnmodifiableXxx" strongly suggests immutability, the class > name "ReadonlyXxxFacade" does not. It seems to me that, as the Collections.unmodifiable*() methods suggest, "unmodifiable" does not mean "immutable", but rather mean what you call "readonly". "Unmodifiable" is a property of the interface (or proxy) type, i.e. the (observable) object state cannot be modified via that interface/proxy (but possibly via some other one), whereas "immutable" is a property of the class, i.e. instances of such a class don't ever change their (observable) state throughout their lifetime.
In any case, however they are named, these are two distinct concepts (immutability implies unmodifiability, but not the other way round), and their implementation will look different accordingly.
-- Niklas Matthies
Ingo R. Homann - 25 Oct 2006 15:29 GMT Hi,
>>Why should it be impossible to assign the returned value to a variable >>of type UnmodifiableInt to document that the variable will not be >>modified? > > Because the user of the Unmodifiable should be able to rely on it not, in fact, > being modified ? Well, I explained my point of view to this in a post before:
'Of course it is not "save" because if you have a reference of type UnmodifiableInt, it may point to an object of type ModifiableInt, so that you could do a cast. But on the other hand, casts are always somehow "unsafe"... (IIRC its the same with 'const' which you can "cast away") On the other hand, even immutable Types like java.lang.String can be modified (using reflection).'
Ciao, Ingo
Oliver Wong - 25 Oct 2006 15:33 GMT > Hi, > [quoted text clipped - 11 lines] > > Now, why should it be impossible to pass a ModifiableInt to that method? It depends on the situation, of course, but what if foo, for example, uses i as the key in a hashtable, on the assumption that the hashcode for i will never change. Then passing in a ModifiableInt might cause a lot of problems.
You could simulate your intended behaviour in the 3-class (or 2-class+1-interface) design as:
void foo(Int i) { ... }
Where Int is the interface/class which only has the getter, but makes no guarantee about whether or not i is immutable. I.e. you could pass ImmutableInt or MutableInt to foo, because both classes implement/extend Int.
> And vice versa: Consider a method is returning an ModifiableInt: > > ModifiableInt foo() {...} > > Why should it be impossible to assign the returned value to a variable of > type UnmodifiableInt to document that the variable will not be modified? Similarly, you could assign this to a reference of type Int if you don't care about modifiability.
However, I realize now that I had assumed "unmodifiable" was synonymous with "immutable", but Chris' and Niklas' posts indicate that some programmers may interpret a difference between these two terms.
- Oliver
Ingo R. Homann - 25 Oct 2006 15:37 GMT Hi,
>>void foo(UnmodifiableInt i) {...} >> [quoted text clipped - 4 lines] > will never change. Then passing in a ModifiableInt might cause a lot of > problems. Ah, OK, perhaps that's what Chris meant as well (I interpreted his answer diffently (that the value could be changed by casting the reference to a ModifiableInt)... post cancelled).
Good reason!
Ciao, Ingo
Lasse Reichstein Nielsen - 25 Oct 2006 16:06 GMT >> void foo(UnmodifiableInt i) {...} >> [quoted text clipped - 4 lines] > will never change. Then passing in a ModifiableInt might cause a lot of > problems. Nevermind the problems, just the name is enough to disqualify this approach. After all, one would have to say: "ModifiableInt is-a UnmodifiableInt" That's incorrect, so either the names or the inheritance is wrong.
If anything, it should be something like ModifiableInt and ReadableInt, because the modifiable int is a readable int.
/L
 Signature Lasse Reichstein Nielsen - lrn@hotpop.com DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html> 'Faith without judgement merely degrades the spirit divine.'
Niklas Matthies - 25 Oct 2006 16:21 GMT > Nevermind the problems, just the name is enough to disqualify this > approach. After all, one would have to say: [quoted text clipped - 3 lines] > If anything, it should be something like ModifiableInt and ReadableInt, > because the modifiable int is a readable int. I would suggest:
interface Int { int getValue(); }
interface ModifiableInt extends Int { void setValue(int value); }
class ImmutableInt implements Int { private final int value; public ImmutableInt(int value) { this.value = value; } public int getValue() { return value; } }
class MutableInt implements ModifiableInt { private int value; public MutableInt(int value) { this.value = value; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } }
-- Niklas Matthies
Oliver Wong - 25 Oct 2006 17:10 GMT > I would suggest: > [quoted text clipped - 16 lines] > public void setValue(int value) { this.value = value; } > } 2 classes + 2 interfaces? Now that's just being crazy. ;)
- Oliver
Niklas Matthies - 25 Oct 2006 18:04 GMT >> I would suggest: >> [quoted text clipped - 18 lines] > > 2 classes + 2 interfaces? Now that's just being crazy. ;) You won't have to use them all at the same time. :) Clients will only "see" either Int, ModifiableInt or (if the guarantee of immutability really needs to be made explicit) ImmutableInt.
You could also drop MutableInt and instead implement it directly in ModifiableInt, but this would remove the flexibility of passing a differently-implemented ModifiableInt to clients. With a simple int this might not seem so probable, but think of ModifiableList or similar.
Take the collections framework for example. A better design would have been to make the Collection interface "unmodifiable" (i.e. with all the mutating methods removed) and provide a ModifiableCollection interface that extends it with the mutating methods. Same for List, Map, Set and so on. Then ArrayList would implement ModifiableList, but you could still simply pass it to clients as just List and be certain that they don't modify it (unless they attempt to cast it to ModifiableList) instead of having to wrap it into an "unmodifiable" proxy. In addition the framework could provide one ImmutableList class that implements List and whose constructor takes an arbitrary List whose elements would be copied to become the contents of the ImmutableList (which would then be really immutable instead of just unmodifiable).
To illustrate the analogy with the interfaces/classes above:
Int ~ List ModifiableInt ~ ModifiableList ImmutableInt ~ ImmutableList MutableInt ~ ArrayList, LinkedList, ...
So, yes, it's one additional interface (ModifiableList) and one additional class (ImmutableList), but it would be much sounder than the existing design (where you get UnsupportedOperationExceptions), and it can be used with all List implementations, so it amortizes pretty well.
Of course, having something like C++'s "const" (or rather its inverse: a "modifiable" qualifier) would be even better.
-- Niklas Matthies
Chris Uppal - 25 Oct 2006 13:30 GMT > 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 [quoted text clipped - 4 lines] > 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
Rogan Dawes - 25 Oct 2006 17:53 GMT >> 2) Only thing I like immutable object, [...] >> I try to have immutable object as [quoted text clipped - 22 lines] > post in this thread -- which does not take account of adaptive optimisation is > probably completely useless.) As a counterpoint to Chris's comments, note that Swing reuses objects in many cases, most notably renderers, for performance reasons.
From the JavaDocs for DefaultTableCellRenderer:
Implementation Note: This class inherits from JLabel, a standard component class. However JTable employs a unique mechanism for rendering its cells and therefore requires some slightly modified behavior from its cell renderer. The table class defines a single cell renderer and uses it as a as a rubber-stamp for rendering all cells in the table; it renders the first cell, changes the contents of that cell renderer, shifts the origin to the new location, re-draws it, and so on. The standard JLabel component was not designed to be used this way and we want to avoid triggering a revalidate each time the cell is drawn. This would greatly decrease performance because the revalidate message would be passed up the hierarchy of the container to determine whether any other components would be affected. So this class overrides the validate, revalidate, repaint, and firePropertyChange methods to be no-ops. If you write your own renderer, please keep this performance consideration in mind.
Rogan
Chris Uppal - 26 Oct 2006 11:35 GMT > As a counterpoint to Chris's comments, note that Swing reuses objects in > many cases, most notably renderers, for performance reasons. Indeed, yes.
Still, I'd like to make a couple of observations (I'm not disagreeing, you understand, just expanding on a good point):
I really should have been clearer that I was refering to the time taken to allocate the memory -- the time taken to initalise the object that will live in that memory is, of course, dependent on the object itself, and may take an arbitrarily long time.
public class Ouch { publich Ouch() { for (;;); } }
;-)
Also, if wouldn't advise newcomers to Java to take Swing as an example of either good /or/ typical Java programming.
-- chris
toton - 26 Oct 2006 15:56 GMT > > As a counterpoint to Chris's comments, note that Swing reuses objects in > > many cases, most notably renderers, for performance reasons. [quoted text clipped - 18 lines] > Also, if wouldn't advise newcomers to Java to take Swing as an example of > either good /or/ typical Java programming. And here, the O.P. ( Myself) is not a new comer in Java World. He professionally worked with some big company in Java (now in a small company, with C++ , and more in research field :( ) . But all those programs are really trivial (You know EJB , Servlet, Hibernate etc) , doesn't require much in-depth knowledge about the language itself. But when it comes with his personal interses, he goes a little deep and explores the possiblities, problems and solutions, as here no timeframe, no rulebook no project leader! His interests are in language construction (among others) and developed a nearly full compiler for Java, which compiles a Java programm, and you can run it! Thanks
> -- chris toton - 26 Oct 2006 15:44 GMT > > 2) Only thing I like immutable object, [...] > > I try to have immutable object as [quoted text clipped - 9 lines] > 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), [quoted text clipped - 8 lines] > 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 [quoted text clipped - 6 lines] > 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 [quoted text clipped - 19 lines] > > 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: [quoted text clipped - 47 lines] > 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 Chris Uppal - 29 Oct 2006 11:34 GMT > 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! Who knows, indeed ;-)
> Heard sun is opening up its C++ sourcecode for JIT , eager to look at > the "bleeding edge" techniques. You already can download the source for the whole 1.6 platform from the same page as the JDK itself. Note that the licence may not be acceptable, so do read it first.
http://java.sun.com/javase/downloads/ea.jsp
> 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! It requires a certain mental agility. Essentially its a matter of reclassifying a task (such as memory management) from "it's challenging and tricky and takes a good programmer to do it properly" to "this stuff is tedious and too boring to bother with -- let the computer do it!". The trick is to be able to change your stance quickly and seamlessly according to the system you're working with at the time ;-)
> 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 "feel" there must be a better way. The only ways I know of are:
1) Pass a huge list of parameters to the constructor -- not nice. 2) Pass an object /containing/ all the data to the constructor. That object (which might be a generic object such as a Map in some cases) is mutable itself, but the object which populates itself from that data is not. 3) The downside of (2) is that you replicate the field list; it might be simpler to keep the "seed" object in your real object as a single field, and use that to hold the data at runtime. It doesn't save an awful lot of code, though. 4) Play games (simple or sophisticated) with access control. For instance all the initialisation could be via package-private methods, or even via private methods (in which case you'd have a static factory method for creating the things).
I think that all the "tricks" you can play with inner or nested classes amount to some variation/combination of the above (albeit, perhaps, packaged more nicely).
In the particular case you describe, I would be tempted to approach this at an OO design level, rather than as a how-to-make-the-code-say-what-I-want level. That's to say, I would be tempted to give the objects the responsibility for populating themselves (taking that job away from the parser). So the object would have ultimate responsibility for parsing; and it would /delegate/ some or all of that responsibility to parser objects which it used internally. The protocol for communication between the parser and the object which used it would be designed so that the parser yielded up information about the various aspects of the input rather than attempting to use that data to construct a Document object itself. That's just a thought, of course, it might make no sense at all for your actual application.
> 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. Fair enough. I hope you enjoy the project !
It wouldn't suit me -- but then I find Java's syntax over-complicated and wouldn't want to spend more time working with it than I had to. My impulse would be to try to do something at the bytecode level (much cleaner than Java for many things), such as adding an annotation to methods which meant "should only be called (directly or indirectly) from the constructor", and then to scan the class files to look for potential violations of the rule. Not really very practical, but it could be fun ;-)
Each to his own...
-- chris
toton - 02 Nov 2006 08:42 GMT > > Maybe someday Java will have an @valueType attribute to "help" memory > > allocation for non-polymorphic objects (final objects), and the [quoted text clipped - 10 lines] > > http://java.sun.com/javase/downloads/ea.jsp Thanks for pointing out the link. Will check it for sure!
> > To put it another way, its a fair bet that the JVM can > > > manage memory faster than you can do it yourself ;-) [quoted text clipped - 7 lines] > able to change your stance quickly and seamlessly according to the system > you're working with at the time ;-) There is a fare chance that a "Good programmer" (not me! ) "sometimes" do better job that a "machine". That is what C++ world claims (I am not too sure about it though).
> > 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. [quoted text clipped - 19 lines] > to some variation/combination of the above (albeit, perhaps, packaged more > nicely). I like 4th Point, and playing with it. But "package" was meant to be something different, rather than access control technique (a name resolution technique).
> In the particular case you describe, I would be tempted to approach this at an > OO design level, rather than as a how-to-make-the-code-say-what-I-want level. [quoted text clipped - 7 lines] > Document object itself. That's just a thought, of course, it might make no > sense at all for your actual application. If Document needs to parse it's data by own, it need to be like a parser. And it need to parse all of the supported data. Document is the "model" ,file is the "view", and parser is the "controller". "I feel" they need to be decoupled.
> > In the meantime writting a Java "preprocessor" which recognizes const > > keyword and do check! However no runtime check. In progress ! Will add [quoted text clipped - 10 lines] > the class files to look for potential violations of the rule. Not really very > practical, but it could be fun ;-) Change in byte-code level needs a new JVM to run my code! I need to modify Jikes RVM then (which I don't think support annotation yet). And surely requires much more knowledge than I have. That is not just feasible form "me" ! But like the solution, if someone do it. Java annotation opened a lots of opportunity, which otherwise was only possible through language extension.
> Each to his own... > > -- chris Chris Uppal - 02 Nov 2006 14:37 GMT > I like 4th Point, and playing with it. But "package" was meant to be > something different, rather than access control technique (a name > resolution technique). I don't know how much the package mechanism was originally intended as a namespace separation feature, and how much as a code grouping feature, but it has certainly proved to be mostly useful (and used) for the latter. The namespace separation is of little use unless there are actual name clashes, but if there are name clashes then the code is in trouble even /if/ the compiler is able to disambiguate perfectly. So it's good practise to avoid name clashes (within reason) -- e.g. not calling a class List or Map. And, as a result, namespace separation is rarely needed. But the package-level access control is used /a lot/.
> If Document needs to parse it's data by own, it need to be like a > parser. And it need to parse all of the supported data. That's not what I meant. I said that it had /responsibility/ for parsing the data -- that isn't at all the same thing as it containing any parsing code (the responsibility could be, and would be, delegated). The point (in this particular design option) is that the users of Documents don't know about Parser objects -- only the Documents themselves do.
> Document is the > "model" ,file is the "view", and parser is the "controller". "I feel" > they need to be decoupled. I'm sorry, but I don't understand that. I always get confused when people start talking about MVC outside its original application domain (constructing GUIs). Even if I can see some sort of resemblance between the components' roles and those of their "equivalents" in classic MVC, I can very rarely see any point in making the comparison (I don't usually see how the metaphor makes the concepts any clearer).
> Change in byte-code level needs a new JVM to run my code! I need to > modify Jikes RVM then (which I don't think support annotation yet). And > surely requires much more knowledge than I have. As a matter of fact Java bytecode has remained very stable over the years -- much more so than Java the language. And of course, you don't need a whole JVM just to analyse the bytecode -- there are several libraries available which will do that for you. ASM seems to be the most popular these days. I'm not at all urging you to become a bytecode expert (you seem to be having enough fun with compilers for now ;-), but bytecode analysis is easier (and more interesting[*]) than I think most Java programmers realise.
-- chris
([*] if you have the right kind of mind ;-)
Arne Vajhøj - 31 Oct 2006 01:41 GMT > 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! Probably never.
That kind of things should be left to the compiler.
Arne
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|