To new or not to new

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

To new or not to new

Alejandro Martínez
Hello list. I'm searching for the opinion of experienced developers:

In which case do you create specialized class message for instantiating an object?

I think two factors are fundamental:
1) You want to enforce correcteness of your objects by making sure they are complete, so you "minimize" #new and provide specialized messages for creation.
2) You do not want to enforce anything until real usage experience shows you which messages you must "promote" to the class side.

My personal view is 2) would be more humble at first, but since this is a question so dependent of the domain you're implementing and your knowledge about it, I'd like to know which patterns or approaches have you seen or taken through the years.
Thanks.



Reply | Threaded
Open this post in threaded view
|

Re: To new or not to new

Colin Putney

On Sep 27, 2007, at 9:58 PM, Alejandro Martínez wrote:

> In which case do you create specialized class message for  
> instantiating an object?
>
> I think two factors are fundamental:
> 1) You want to enforce correcteness of your objects by making sure  
> they are complete, so you "minimize" #new and provide specialized  
> messages for creation.
> 2) You do not want to enforce anything until real usage experience  
> shows you which messages you must "promote" to the class side.
>
> My personal view is 2) would be more humble at first, but since  
> this is a question so dependent of the domain you're implementing  
> and your knowledge about it, I'd like to know which patterns or  
> approaches have you seen or taken through the years.


Hi Alejandro,

In my experience, the thing to be thinking about is clarity. Will  
creating a specialized instance-creation method make your code easier  
to understand? If so, do it.

Take the class Semaphore as an example. #forMutualExclusion is a  
great method. The implementation is pretty trivial, you could replace  
all the senders with "Semaphore new signal" without complicating the  
code much. But you'd have a huge loss in terms of clarity. With  
"Semaphore forMutualExclusion" it's obvious what you're doing, so  
much so that you don't even have to remember the details of how to  
use semaphores as mutexes. #forMutualExclusion and #critical: are all  
you need.

Don't worry about 1). You can't "enforce" anything in Smalltalk  
anyway, and if you could it would just make life difficult for the  
next guy who has to deal with the code - and chances are good that  
guy is you. Instead, try to make life easier for the users of the code.

Don't worry about 2) either. If experience shows you a better way to  
initialize objects of a particular class, use it. You can have more  
than one instance-creation method if you want, or update all the  
senders of the old method to use the new one. Don't worry at all  
about doing one thing and then changing your mind later.

One final thought. I find that I like to organize an object's state  
according to its life-cycle. If there are certain variables that are  
set when an object is created and are never changed over its  
lifetime, I create a specific constructor for those variables, and a  
single initializer method something like #setFoo:bar:baz: on the  
instance side. I might have getters for those ivars, but almost never  
have setters. This is the kind of that often forms the "identity" of  
the object, so having specialized constructor and initializer methods  
helps make that clear.

On the other hand, I usually don't include volatile state in  
specialized constructors. Instead, I create both getters and setters,  
possibly with lazy initialization, and leave it to the users to  
supply that volatile state. Combining these patterns might yield  
something like this:

(House atAddress: '123 Main St.')
        color: Color blue;
        bedrooms: 3;
        yourself

The address of the house won't change, but it might get a new coat of  
paint, or an addition. These aren't hard and fast rules, of course,  
but habits that I seem to follow.

Colin
Reply | Threaded
Open this post in threaded view
|

Re: To new or not to new

Boris.Gaertner
In reply to this post by Alejandro Martínez
 [hidden email]  wrote:
Hello list. I'm searching for the opinion of experienced developers:

In which case do you create specialized class message for instantiating an object?

I think two factors are fundamental:
1) You want to enforce correcteness of your objects by making sure they are complete, so you "minimize" #new and provide specialized messages for creation.
2) You do not want to enforce anything until real usage experience shows you which messages you must "promote" to the class side.
Point 1 is indeed fundamental: Specialized instance creation methods are
used to create fully initialized instances. Beautiful examples of that
approach can be found mainly in the old parts of Squeak. Have a
look e.g. at
   PluggableListView
   PluggableButtonView
   PluggableTextView
   PopUpMenu
   SelectionMenu
or at classes Browser  and Inspector.
PluggableListView has one general class method that creates
a fully initialized instance. That method is also sent by two
simpler class methods that provide reasonable default values
for unneeded features of an instance.
In PopUpMenu a general class method is #labelArray:lines:
its simplified variant is #labelArray:
All the classes that I just mentioned provide both general
and specialized class methods for instance creation.
That approach is, in my opinion, an example of careful
class design that should be followed. I agree however
that some additional work is needed to find out required
initial values and suitable default values for features
that are not always needed.
 
Additional remark: In the absence of other documentation
a set of specialized instance creation method helps you to
understand how you should use a class. At times this can
be very helpful.
 
Second additional remark:
 
 myClass new
   initVariable1: <anExpression1>;
   initVariable2: <anExpression2>;
   initVariable3: <anExpression3>.
 
is of course possible, but it does not surpass the
quality of code that is generated by simple tools.
As we are not code generators we should perhaps
try to do better.  :-)
 
Greetings,
Boris