initializeWith* and constructors

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

initializeWith* and constructors

Peter Uhnak
It seems to me that Smalltalkers are not very fond of constructors and I can't comprehend why.

If for example I want to create object X that _needs_ object Y, then I would have to make a Y accessor.

X>>y: anY
    y := anY

but this makes no sense as I can still change the `y` object at later date breaking everything.

An alternative is having:

X>>initializeWithY: anY
    y := anY.
    self initialize.

X>>y: anY
    ^ self basicNew initalizeWithY: anY.

However I see only 59 initializeWith* methods (in about 6 packages) compared to 2302 initialize methods. Thus I am deducing that doing this is not very common.

Am I missing something or am I trying to unnecessarily constraint the user and I should just trust™ him that he knows what he should use?

As a user of an interface I would prefer not to have useless things available that would just break things.

Thanks,
Peter
Reply | Threaded
Open this post in threaded view
|

Re: initializeWith* and constructors

Sergio Fedi
First I would like to make the distinction between user as the user of an application and user as the user of an object.

How we program has to do more with the user as a programmer using an object.

In that case I program assuming the programmers that will use my object know what they are doing.
Because I can't do anything otherwise.

Another thing is that restricting access to a variable makes sense for code that uses the object (telling them not to mess or change this variable)
but that restriction does not make sense for other kind of objects: Factories, constructor methods, editor objects, etc.

Reply | Threaded
Open this post in threaded view
|

Re: initializeWith* and constructors

Ben Coman
In reply to this post by Peter Uhnak
There are other conventions like: 

* set...
   * Delay class >> forMilliseconds: aNumber
^ self new setDelay: aNumber forSemaphore: Semaphore new

* initializeFor...
   * DynamicMessageImplementor class>>#for:in:
^ self new initializeFor: aMessage in: aClass

* from:to:...
    * Bezier2Segment class>>#from:to:via:
^self new from: startPoint to: endPoint via: viaPoint

I dug a bit to produce this script so you can view more yourself...

    protocols := (Protocol allInstances select: [ :p | p name = 'instance creation' ]) flatCollect: [ :p | p methods ].
    methods := protocols select: [ :m | (m occurrencesOf: $:) > 1 ].
    implementors := methods flatCollect: [ :m | m implementors ].
    constructorExamples := implementors select: [ :i | (i sourceCode includesAll: 'new') or: [ i sourceCode includesAll: 'basicNew' ] ]. 

cheers -ben


On Sat, May 2, 2015 at 9:02 PM, Peter Uhnák <[hidden email]> wrote:
It seems to me that Smalltalkers are not very fond of constructors and I can't comprehend why.

If for example I want to create object X that _needs_ object Y, then I would have to make a Y accessor.

X>>y: anY
    y := anY

but this makes no sense as I can still change the `y` object at later date breaking everything.

An alternative is having:

X>>initializeWithY: anY
    y := anY.
    self initialize.

X>>y: anY
    ^ self basicNew initalizeWithY: anY.

However I see only 59 initializeWith* methods (in about 6 packages) compared to 2302 initialize methods. Thus I am deducing that doing this is not very common.

Am I missing something or am I trying to unnecessarily constraint the user and I should just trust™ him that he knows what he should use?

As a user of an interface I would prefer not to have useless things available that would just break things.

Thanks,
Peter

Reply | Threaded
Open this post in threaded view
|

Re: initializeWith* and constructors

Carlo-2
Hi

Kent Beck came up with some useful idioms in his book Smalltalk Best Practice Patterns. 
One of them was the 'Creation Parameter Method' which is basically the "set" based initialisation method (which Ben mentioned below). This idiom used in conjunction with the "Complete Creation Method" I believe helps communicate "how can I create a valid instance?" to users of your objects.

Cheers
Carlo


On 02 May 2015, at 4:52 PM, Ben Coman <[hidden email]> wrote:

There are other conventions like: 

* set...
   * Delay class >> forMilliseconds: aNumber
^ self new setDelay: aNumber forSemaphore: Semaphore new

* initializeFor...
   * DynamicMessageImplementor class>>#for:in:
^ self new initializeFor: aMessage in: aClass

* from:to:...
    * Bezier2Segment class>>#from:to:via:
^self new from: startPoint to: endPoint via: viaPoint

I dug a bit to produce this script so you can view more yourself...

    protocols := (Protocol allInstances select: [ :p | p name = 'instance creation' ]) flatCollect: [ :p | p methods ].
    methods := protocols select: [ :m | (m occurrencesOf: $:) > 1 ].
    implementors := methods flatCollect: [ :m | m implementors ].
    constructorExamples := implementors select: [ :i | (i sourceCode includesAll: 'new') or: [ i sourceCode includesAll: 'basicNew' ] ]. 

cheers -ben


On Sat, May 2, 2015 at 9:02 PM, Peter Uhnák <[hidden email]> wrote:
It seems to me that Smalltalkers are not very fond of constructors and I can't comprehend why.

If for example I want to create object X that _needs_ object Y, then I would have to make a Y accessor.

X>>y: anY
    y := anY

but this makes no sense as I can still change the `y` object at later date breaking everything.

An alternative is having:

X>>initializeWithY: anY
    y := anY.
    self initialize.

X>>y: anY
    ^ self basicNew initalizeWithY: anY.

However I see only 59 initializeWith* methods (in about 6 packages) compared to 2302 initialize methods. Thus I am deducing that doing this is not very common.

Am I missing something or am I trying to unnecessarily constraint the user and I should just trust™ him that he knows what he should use?

As a user of an interface I would prefer not to have useless things available that would just break things.

Thanks,
Peter


Reply | Threaded
Open this post in threaded view
|

Re: initializeWith* and constructors

stepharo
But remember that it was before new invoke initialized was introduced.
We introduced back in squeak because it helps newcomers: they do not have to understand metaclass the first day.

Stef

Le 4/5/15 00:40, Carlo a écrit :
Hi

Kent Beck came up with some useful idioms in his book Smalltalk Best Practice Patterns. 
One of them was the 'Creation Parameter Method' which is basically the "set" based initialisation method (which Ben mentioned below). This idiom used in conjunction with the "Complete Creation Method" I believe helps communicate "how can I create a valid instance?" to users of your objects.

Cheers
Carlo


On 02 May 2015, at 4:52 PM, Ben Coman <[hidden email]> wrote:

There are other conventions like: 

* set...
   * Delay class >> forMilliseconds: aNumber
^ self new setDelay: aNumber forSemaphore: Semaphore new

* initializeFor...
   * DynamicMessageImplementor class>>#for:in:
^ self new initializeFor: aMessage in: aClass

* from:to:...
    * Bezier2Segment class>>#from:to:via:
^self new from: startPoint to: endPoint via: viaPoint

I dug a bit to produce this script so you can view more yourself...

    protocols := (Protocol allInstances select: [ :p | p name = 'instance creation' ]) flatCollect: [ :p | p methods ].
    methods := protocols select: [ :m | (m occurrencesOf: $:) > 1 ].
    implementors := methods flatCollect: [ :m | m implementors ].
    constructorExamples := implementors select: [ :i | (i sourceCode includesAll: 'new') or: [ i sourceCode includesAll: 'basicNew' ] ]. 

cheers -ben


On Sat, May 2, 2015 at 9:02 PM, Peter Uhnák <[hidden email]> wrote:
It seems to me that Smalltalkers are not very fond of constructors and I can't comprehend why.

If for example I want to create object X that _needs_ object Y, then I would have to make a Y accessor.

X>>y: anY
    y := anY

but this makes no sense as I can still change the `y` object at later date breaking everything.

An alternative is having:

X>>initializeWithY: anY
    y := anY.
    self initialize.

X>>y: anY
    ^ self basicNew initalizeWithY: anY.

However I see only 59 initializeWith* methods (in about 6 packages) compared to 2302 initialize methods. Thus I am deducing that doing this is not very common.

Am I missing something or am I trying to unnecessarily constraint the user and I should just trust™ him that he knows what he should use?

As a user of an interface I would prefer not to have useless things available that would just break things.

Thanks,
Peter