Peter Norell
Posts: 5
Nickname: bithir
Registered: Dec, 2002
|
|
Re: Article on the "Evils of new" ?
|
Posted: Dec 17, 2002 10:52 AM
|
|
A interesting article where the author raises many good ideas but at the core I do not agree with him.
I'll try to show my arguments why I am against the proposed reasons. Quotes from the article will be presented in italic. I am sorry for those that find italic hard to read but the choice was between that and bold.
Sometimes only a few instances of a class are desired. Imagine a class representing ASCII characters. There are only 256 of those. If the class is immutable and doesn't carry any other information, only 256 instances of the class need ever exist--more would just clutter memory. For a more dramatic example, consider the Boolean class: Only two instances are ever necessary, one for True and one for False. In addition to saving memory, having only one instance per value also allows testing for equality using the "==" operator, instead of the slower "equals" method.
What the article author obviously wants is to reuse a subset of available immutable classes. He points out that people are succumbing to bad habits when programming and constructing new Boolean-objects instead of reusing the two immutable instances that exist. He then goes on talking about ways for the writer (the developer in this instance) sometimes would like to have ways to return an instance for reuse.
These are all usefull features but do we gain much for the loss of clarity? No, it would complicate the language quite a bit and the developers that can't be bothered to use Boolean.TRUE / FALSE for their constructs will not bother to return an object for reuse either.
For a more sophisticated and (currently) hypothetical example, consider the Integer class. There are many possible instances of this class ? too many to cache them all ? but we might conjecture that some values are more common than others. Probably Integer objects representing the numbers from -2 to 100 are more likely to occur than others. A clever implementation could cache objects for these numbers, saving the time and storage involved in their creation.
The author touches the fact that the design pattern flyweight more or less achives exacly a cache of objects..
The concept of object pooling is seldom recommended as most of todays JVM's uses generational GC to such extent that if you are not carefull the use of object pooling might actually hinder rather than increase the performance. This is especially true for short-lived objects.
The OO solution would be to use either some sort of well known solution for object-creation, like Singleton, Flyweight or Factory. Utilising these extensions we can easily accomplish what is requested.
There is offcourse no good way for a standard library to know what set of immutables that are most likely to occur than others. This is something that an independant developer will have to take into consideration along with performance gains, memory usage and there choice of GC for their JVM.
In other situations, the idea is not to avoid creating an object, but to create it somewhere other than the heap. For instance, in a distributed system, you may want to instantiate an object on another machine.
This are usually very specialised requirements and far from common. They sacrificed quite a few features from C++, like operator overloading for the language to be more clear. Adding such specialised functionality would serve only to obscure the language. The author uses the real-time java as an example, where it is stated that the real-time specification has ways to create objects in other places than the heap to ensure gc will not hinder the real-time aspect. This is a good example of a specialised need and the solution is based upon the limitation on how real-time java have to behave and on the plattforms real-time java would be used.
For specialised needs, specialised solution should be used. For the authors example of using it in a distributed system, probably want to make sure it is also load-balanced, fault tolerant object creation. Adding these capabilities into java would hamper it's use for sure and would make life much more complicated. Developers have already trouble to grasp the concept of Proxy's used by J2EE.
The first step in solving any of these memory allocation issues is to declare all constructors private, or at least protected if you wish to support subclasses. Making the constructors private is safer ? you can be sure that no clients of your class can use new to instantiate it ? but also makes it impossible to declare subclasses. There is a tradeoff between allowing inheritance and encapsulating creation.
This obviously has two assumptions: 1) It is an immutable class 2) The standard immutable classes has to "know" what instances that will be most common.
The author then gives an example using Booleans, which by far is the absolutly easiest example as it only can contain two different values, true of false. I am bound to agree here that it would have been a good idea to make Boolean's constructor private, but I would not agree on the same for Integers. I presume the reasoning was that they wanted to ensure that the behaviour for all immutable Number subclasses to stay the same, and rely on the fact that developers would consider on how to utilise the Boolean class.
The article also touches the problem with using static factory methods as they are inherited and can cause trouble in when developers forget to code methods. This is always the risk when creating subclasses and is an explicit functionality in the inheritance model. Forgetting to implement the factory method will offcourse cause errors but so would it to forget to implement any of the other methods that the subclass was supposed to override.
When I write new Rectangle(), I always get a Rectangle, never anything else, and in particular never a subclass of Rectangle.
It would be a very pleasant feature to be able to get subclasses of an Rectangle, but the added complexity of setting up factories, ways to register subclasses to the factories would make java much harder to learn. The complexity for the extensive number of classes already existing makes me reluctant of making the visualisation of how they interact between each other more abstract.
The idea is sound, but it is way low on my scale of priorities. Much of what the articles describes have "software" solutions. As it is, the new keyword might not be ideal to use, but adding factoring methods or language constructs for a more polymorphic creation is more force than the problem recalls for. To equalise the new keyword with goto is harsh and maybe not called for, it might not be the ultimate solution, but it definiatly does the thing at the moment. For the specialised solutions out there where object creation is a big problem, the Factory support will be provided as an infrastructure component. J2EE is an example on how infrastructure is used to support the pooling and to hide the creation of objects behind abstraction.
This rambling was brought to you by Peter Norell Ps. My ending is a bit rush as I am about to depart for my train, any gramatical or other language errors we blame on the stress. :-)
|
|