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

Chris Muller asqueaker at gmail.com
Sat Dec 21 19:21:57 UTC 2013


I should not have called it an "anti-pattern" because it has the same
_principles_ as CPM.  It's just that the implementation repeats itself
in all the initializeWith methods ("self initialize") whereas CPM says
it only once.  CPM also reinforces the idea that there is trying to be
just _one way_ to create objects and that is with #new, not sometimes
new and sometimes basicNew.

That leaves the "set" vs. "initializeWith" nomenclature.  The former
is more easier to type and say, follows documented best-practice
convention, and leaves no doubt about what it does, and _only_ what it
does.  "set" means it _only_ populates the state.  "initializeWith..."
means any number of "actiony" stuff it might do, possibly calling
other builder methods, etc.  That building stuff should be abstracted
away from simply populating the vars to ensure a well-formed object.
Colins pattern commingles those two.



On Sat, Dec 21, 2013 at 12:02 PM, Chris Muller <ma.chris.m at gmail.com> wrote:
>>>> Why make the AddPrefixNamePolicy mutable? That seems like a bad idea.
>>>> Unless there's some seriously major gain to be had, we should _not_
>>>> add setters. The "basicNew initializeWithFoo:" idiom makes it clear
>>>> that "AddPrefixNamePolicy new" will not result in a properly
>>>> initialised object. It avoids giving people the impression that it's
>>>> OK to monkey with the object's state. It's also the closest we can get
>>>> to immutability, given that the only way we can initialise an object's
>>>> state correctly is by sending it messages. (I realise the idiom's not
>>>> in SBPP, but sometimes we can improve on the classics.)
>>>>
>>>> I like how you renamed lots of parameters to indicate the kind of
>>>> things they ought to contain ("aNamespace" -> "aDictionary"), but
>>>> please, no setters.
>>>
>>> Yeah, both things are simply documented best-practice conventions.
>>> It's best not to call basicNew except for serialization frameworks or
>>> otherwise with a good reason to, otherwise #initialize won't get
>>> called from the one place it should be called from.
>>
>> My point is that I don't think you should send #new at all, because
>> that suggests that you could have an AddPrefixNamePolicy with no
>> prefix.
>
> No it doesn't.  #new is how you create initialized instances.
> #basicNew is how a framework creates empty instances.
>
> Neither "implies" anything about proper construction of the object.
> For that you should look at the class-side protocols.  Maybe what you
> want is to override #new as a shouldNotImplement or signal an Error or
> something like that, but I don't think that's necessary -- again,
> because the *protocols* define 'instance creation' methods.
>
> When you use a class, you need look at it first -- understand its API
> before you go sending messages.
>
>>> Now, I've heard the suggestion to name these methods as "myPrefix:
>>> prefixString myNamespace: aDictionary", so that, should a developer
>>> ever think he wants to use them, it will look and read awkwardly in
>>> the calling code.
>>>
>>> But that relies on a convention for "privatizing" that no other
>>> private methods can afford.
>>
>> As does that #new prefix: cascade.
>
> No it doesn't.  "initialize/release" methods are private, they're
> called by the system and everyone knows that.
>
>> I almost entirely agree with you. Except that I think that calling
>> #basicNew and initialising within the #initializeWithFoo: methods is
>> superior because
>> * you don't need a setter (as in, you don't need a method that looks
>> and smells and tastes exactly like a classic
>
> There are no setters here Frank!  It's a Constructor Parameter Method,
> not a setter method.  Setter methods do not begin with "set" as they
> do in Java.  Setter methods do not set multiple variables like CPM's
> do.
>
>> expose-my-state-for-mutation setter.
>
> What the heck does the #initializeWith: method do?  Same exact thing!
> It's a mutator!
>
>> * #initializeWithFoo: tells you the ways you can construct a valid
>> instance, and if you want to construct an _invalid_ one you have to
>> work at it - actively subvert the API.
>
> Same exact thing with CPM's.  You cannot create an invalid instance
> using this pattern.  You really need to read the pattern in Kent Becks
> book.
>
>> * #initializeWithFoo: tells you much louder exactly what it will do,
>> where #setFoo: (a) looks like a Java-style mutator and (b) suggests
>> that you can (partly!) _reinitialise_ an object. Worse, #setFoo: only
>> partially initialises the object, where #initializeWithFoo: completely
>> initialises an object.
>
> Wrong.  It's not "setFoo", it's #setFoo:bar:diddle:daddle:.  Take a
> look at Point class>>#x:y:.  It bypasses #new in favor of #basicNew
> for performance, but otherwise follows the CPM pattern correctly.
>
>> So in the end we're arguing about two conventions that do more or less
>> the same thing. I don't see any _improvement_ in using #new, and in
>> fact see several (admittedly minor) downsides. So what's the point
>> then of "fixing" this?
>
> Because your code should say everything just once.  For the
> initializeWith pattern, you have to call #initialize from each one, so
> you're repeating yourself.
>
> The expectation is that #initialize is called when creating new
> objects.  If new state is added to the object later that is not set by
> the constructor, it will get initialized without having to remember to
> cahnge the constructor.  Calling basicNew is just wrong.
>


More information about the Squeak-dev mailing list