[squeak-dev] The Trunk: Environments-cmm.38.mcz

Levente Uzonyi leves at elte.hu
Mon Dec 23 00:37:08 UTC 2013


On Sun, 22 Dec 2013, Chris Muller wrote:

> So here is another correct example of CPM when more than one variable
> needs initialized.
>
> Your home-brew version of CPM does the same thing, but it 1) violates
> the rule to say things once and only once, 2) has #initialize getting
> called from any of half-a-dozen places rather than the ONE place, 3)
> doesn't factor the behavior of simply *constructing* a _well-formed
> object_ from the behavior of fully initializing it (i.e.., building up
> a large cache).

If you follow this pattern, then #initialize will become a lie, because 
it's not initializing anything. You do the actual initialization in the 
#set* methods.
Also your third point applies to this CPM method (or what) too, because 
#new will not create a _well-formed object_, the #set* methods will do 
that. (Yes, there are cases when an object without being initialized 
_with a parameter_ is not a well-formed object).

You're thinking more into #initialize than what it actually is. It's 
nothing more than a hook, which is usually called when an object is 
created, but there are no guarantees. I may override #new whenever I want, 
or I might call #basicNew. I'm sure there are plenty of classes in the 
current Trunk, which don't use #initialize at all.


Levente

P.S.: AFAIK #initialize is a "new concept", which was not part of ST-80.
P.P.S.: Just because someone (Kent Beck in this case) is doing something 
differently than you, it doesn't mean it's better than what you do.
P.P.P.S.: Most Smalltalkers dislike the #set* methods for some reason.
>
>>>> 1) each class that declares instance variables has exactly one
>>>> initialization method
>>>
>>> Well then you can't have more than one constructor type then.  Not all
>>> objects can follow a path down to a single constructor on the
>>> class-side that ends up calling #initializeWtih:...
>>
>> Why not? I've never found this to be an issue.
>>
>>>
>>> In several cases,
>>> you'll need #initializeWithThis: and #initializeWithThat:.  And, in
>>> both cases, you want to call #initialize from the top of them.  That's
>>> repeating yourself and unconventional.
>>
>> Right. That's why the rule is one initializer.
>
> What is an "initializer?"  Is that an #initialize method or an
> #initializeWith... method?  If the former, it makes no sense to say
> it's a rule to only have one because that's all you COULD have.  If
> the latter, you're contradicting yourself in the above paragraph.
>
>>>> 2) each initialization method must leave the instance in a valid state
>>>
>>> Of course, as does any initialization method like CPM methods.
>>
>> Not so. If your class has ivars 'foo' and 'bar' and it needs both of them to
>> have values for the object to be valid, then neither #setFoo: nor #setBar:
>> leave the object in a valid state. You have to call both of them to get a
>> fully-initialized object. But #initializeWithFoo:bar: leaves the object in a
>> valid state.
>
> The above makes it very clear you haven't read CPM.
>
> That's why I've committed this change, as second example of CPM
> showing it does the same thing, but without repeating itself and
> without the other issues associated with the home-brew version.
>
>>>> 3) each initialization method is named verbosely starting with
>>>> 'initializeWith' and describes its parameters
>>>
>>> The ONLY reason you call it "initializeWithThis:that:other:thing:"
>>> instead of "setThis:that:other:thing:" is because you want to repeat
>>> yourself by calling #initalize at the top of each method.
>>
>> The reason to call it #initializeWithThis:that: is that it initializes the
>> object with this and that. If you like consider this an instance of
>> "intention-revealing selector".
>
> But what if I ONLY want a minimally well-formed instance, (e.g.,
> minimum number of inst-vars set to make a well-formed instance, but
> not, say, 'cache' variables which are derived from the minimum vars --
> CPM does the minimum, initializeWith:... implies to build the cache as
> well).
>
>>>> 6) there is one or more class-side constructors which send #basicNew and
>>>> the
>>>> initialization message
>>>
>>> Why basicNew instead of new?  Honestly, there's no good reason for
>>> that and it forces you to repeat yourself in all of your
>>> #initializeWith: methods.
>>
>> Because #new calls #initialize. When following this pattern, #initialize
>> still gets called, but by a subclass initializer, not by the constructor. We
>> want to avoid calling #initialize twice.
>
> Exactly.  You've articulated one of the problems with your home-brew
> CPM.  You're doing this unnecessary dance with calling #basicNew and
> #initialize yourself when all you need to say is, simply, #new.
> That's a definite regression of CPM.
>
> On Sun, Dec 22, 2013 at 11:23 AM,  <commits at source.squeak.org> wrote:
>> Chris Muller uploaded a new version of Environments to project The Trunk:
>> http://source.squeak.org/trunk/Environments-cmm.38.mcz
>>
>> ==================== Summary ====================
>>
>> Name: Environments-cmm.38
>> Author: cmm
>> Time: 22 December 2013, 11:23:45.064 am
>> UUID: bcae5b17-4e55-4b16-be84-90fc1e283ae4
>> Ancestors: Environments-cmm.37
>>
>> Use proper implementation of Constructor Parameter Method.
>>
>> =============== Diff against Environments-cmm.37 ===============
>>
>> Item was changed:
>>   ----- Method: EnvironmentInfo class>>name:organization:packages: (in category 'as yet unclassified') -----
>>   name: aString organization: aSystemOrganizer packages: aPackageOrganizer
>> +       ^ self new
>> +               setName: aString
>> -       ^ self basicNew
>> -               initializeWithName: aString
>>                 organization: aSystemOrganizer
>>                 packages: aPackageOrganizer!
>>
>> Item was removed:
>> - ----- Method: EnvironmentInfo>>initializeWithName:organization:packages: (in category 'as yet unclassified') -----
>> - initializeWithName: aString organization: aSystemOrganizer packages: aPackageOrganizer
>> -       self initialize.
>> -       name := aString.
>> -       organization := aSystemOrganizer.
>> -       packages := aPackageOrganizer.
>> -       !
>>
>> Item was changed:
>> + ----- Method: EnvironmentInfo>>name (in category 'access') -----
>> - ----- Method: EnvironmentInfo>>name (in category 'as yet unclassified') -----
>>   name
>>         ^ name!
>>
>> Item was changed:
>> + ----- Method: EnvironmentInfo>>organization (in category 'access') -----
>> - ----- Method: EnvironmentInfo>>organization (in category 'as yet unclassified') -----
>>   organization
>>         ^ organization!
>>
>> Item was changed:
>> + ----- Method: EnvironmentInfo>>packages (in category 'access') -----
>> - ----- Method: EnvironmentInfo>>packages (in category 'as yet unclassified') -----
>>   packages
>>         ^ packages!
>>
>> Item was changed:
>> + ----- Method: EnvironmentInfo>>printOn: (in category 'printing') -----
>> - ----- Method: EnvironmentInfo>>printOn: (in category 'as yet unclassified') -----
>>   printOn: aStream
>>         aStream nextPutAll: name.
>>         aStream nextPutAll: 'Info'!
>>
>> Item was added:
>> + ----- Method: EnvironmentInfo>>setName:organization:packages: (in category 'initialize-release') -----
>> + setName: aString organization: aSystemOrganizer packages: aPackageOrganizer
>> +       name := aString.
>> +       organization := aSystemOrganizer.
>> +       packages := aPackageOrganizer!
>>
>>
>
>


More information about the Squeak-dev mailing list