Stupid Question?

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

Stupid Question?

Richard Eng
I have a stupid question:  How do you pass information into the #initialize
method at object creation time? You can't use any of the instance methods or
accessors because they don't yet exist! So how do you pass information in?

Thanks,
Richard



Reply | Threaded
Open this post in threaded view
|

Re: Stupid Question?

NorbertHartl

On Wed, 2008-01-16 at 08:46 -0500, Richard Eng wrote:
> I have a stupid question:  How do you pass information into the #initialize
> method at object creation time? You can't use any of the instance methods or
> accessors because they don't yet exist! So how do you pass information in?

You do not! :) If you want to pass values into an object you
may do this with your own constructor for the object. This
contructor creates a new object and passes some values to
it.

Example:

MyObject class>>on: aStream
   ^ self new
      stream: aStream

in your code you do:

myObject := MyObject on: aStream

hope this helps,

Norbert


Reply | Threaded
Open this post in threaded view
|

Re: Stupid Question?

Zulq Alam-2
In reply to this post by Richard Eng
Hi Richard,

The instance variables and methods, including accessors, exist when the
object is created. They do not depend on the initialize method. Thus you
can access any instance variable or call any defined method, such as
accessors, at any time after creation. Whether they have a value or
return anything useful depends on your object and how you *chose* to
initialize it.

The use of #initialize is a convention to set-up object state *after*
the object has been created. You do not have to stick to this. For
example, consider the Point class.

On the class side it defines:

x: xInteger y: yInteger
        "Answer an instance of me with coordinates xInteger and
        yInteger."

        ^self basicNew setX: xInteger setY: yInteger

And on the instance side:

setX: xValue setY: yValue

        x _ xValue.
        y _ yValue

So, effectively we have two constructor methods, one on the class side
which passes parameters to the one on the instance side which does all
the work.

In this case, the #initialize methods is never called because the class
side constructor sends #basicNew instead of #new. This makes more sense
if we look at how #new is defined on Behaviour.

new
        "Answer a new initialized instance of the receiver (which is a
        class) with no indexable variables. Fail if the class is
        indexable."

        ^ self basicNew initialize

Some people use #initializeWith???: type methods instead of set???:
methods. I'm not sure which is better.

Having said all that, I often do what Norbert suggests and just call
setter methods from the class side constructor:

MyObject class>>on: aStream
    ^ self new
       stream: aStream;
       yourself

This is great if I just want to set some instance variables and run. The
possible downside is you may not want to have the setter #stream:
around.

Regards,
Zulq.

Richard Eng wrote:

> I have a stupid question:  How do you pass information into the #initialize
> method at object creation time? You can't use any of the instance methods or
> accessors because they don't yet exist! So how do you pass information in?
>
> Thanks,
> Richard
>
>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Stupid Question?

Richard Eng
In reply to this post by Richard Eng
I'm not finding this to be true. I have a class #GSAssignmentList. It has
instance variable #clientId and accessor #clientId:. I do the following:

    self call: (GSAssignmentList new clientId: aValue)

In the #initialize method for GSAssignmentList, I write to the Transcript:

    Transcript cr; show: 'RKE: clientId = ', clientId asString.

It shows 'nil'.

In #renderContentOn:, I write to the Transcript and get aValue, as expected.
This is contrary to what you're telling me *if* the object is created with
#clientId = aValue *before* #initialize starts to execute.

You see, I need the value of aValue in order for #initialize to complete.

Regards,
Richard

----------------
Zulq Alam wrote:

Hi Richard,

The instance variables and methods, including accessors, exist when the
object is created. They do not depend on the initialize method. Thus you
can access any instance variable or call any defined method, such as
accessors, at any time after creation. Whether they have a value or
return anything useful depends on your object and how you *chose* to
initialize it.

The use of #initialize is a convention to set-up object state *after*
the object has been created.



Reply | Threaded
Open this post in threaded view
|

Re: Stupid Question?

Jason Johnson-5
new calls initialize.

On Jan 16, 2008 6:25 PM, Richard Eng <[hidden email]> wrote:

> I'm not finding this to be true. I have a class #GSAssignmentList. It has
> instance variable #clientId and accessor #clientId:. I do the following:
>
>     self call: (GSAssignmentList new clientId: aValue)
>
> In the #initialize method for GSAssignmentList, I write to the Transcript:
>
>     Transcript cr; show: 'RKE: clientId = ', clientId asString.
>
> It shows 'nil'.
>
> In #renderContentOn:, I write to the Transcript and get aValue, as expected.
> This is contrary to what you're telling me *if* the object is created with
> #clientId = aValue *before* #initialize starts to execute.
>
> You see, I need the value of aValue in order for #initialize to complete.
>
> Regards,
> Richard
>
> ----------------
>
> Zulq Alam wrote:
>
> Hi Richard,
>
> The instance variables and methods, including accessors, exist when the
> object is created. They do not depend on the initialize method. Thus you
> can access any instance variable or call any defined method, such as
> accessors, at any time after creation. Whether they have a value or
> return anything useful depends on your object and how you *chose* to
> initialize it.
>
> The use of #initialize is a convention to set-up object state *after*
> the object has been created.
>
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Stupid Question?

Tom Phoenix
In reply to this post by Richard Eng
On Jan 16, 2008 9:25 AM, Richard Eng <[hidden email]> wrote:

> You see, I need the value of aValue in order for #initialize to complete.

In that case, you probably want to move that part of the
initialization code out of #initialize, and then write something like
this:

  MyClass>>clientId: aValue

    clientId := aValue.
    self adjustForClientId: aValue.

Of course, you'll also have to allow for the possibility that an
object may sometimes not be fully initialized. For example, your
#printOn: method may look like this:

  MyClass>>printOn: aStream

    clientId ifNil: [^super printOn: aStream].
    ....

Hope this helps!

--Tom Phoenix

Reply | Threaded
Open this post in threaded view
|

Re: Stupid Question?

Zulq Alam-2
In reply to this post by Richard Eng
Your original statement was that "You can't use any of the instance
methods or accessors because they don't yet exist!". I am saying you can
use them, and the do exist, although they may or may not have a value
depending on how you chose to initialize your object.

If you do not change anything, then #new will send the newly created
object #initialize. To avoid this behaviour you will need to create a
class side method and send #basicNew to create your instance and then
initialize it as you desire. Have a look at the Point example I included.

Regards,
Zulq.


Richard Eng wrote:

> I'm not finding this to be true. I have a class #GSAssignmentList. It has
> instance variable #clientId and accessor #clientId:. I do the following:
>
>     self call: (GSAssignmentList new clientId: aValue)
>
> In the #initialize method for GSAssignmentList, I write to the Transcript:
>
>     Transcript cr; show: 'RKE: clientId = ', clientId asString.
>
> It shows 'nil'.
>
> In #renderContentOn:, I write to the Transcript and get aValue, as expected.
> This is contrary to what you're telling me *if* the object is created with
> #clientId = aValue *before* #initialize starts to execute.
>
> You see, I need the value of aValue in order for #initialize to complete.
>
> Regards,
> Richard
>
> ----------------
> Zulq Alam wrote:
>
> Hi Richard,
>
> The instance variables and methods, including accessors, exist when the
> object is created. They do not depend on the initialize method. Thus you
> can access any instance variable or call any defined method, such as
> accessors, at any time after creation. Whether they have a value or
> return anything useful depends on your object and how you *chose* to
> initialize it.
>
> The use of #initialize is a convention to set-up object state *after*
> the object has been created.
>
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Stupid Question?

Randal L. Schwartz
In reply to this post by Richard Eng
>>>>> "Richard" == Richard Eng <[hidden email]> writes:

Richard> In #renderContentOn:, I write to the Transcript and get aValue, as
Richard> expected.  This is contrary to what you're telling me *if* the object
Richard> is created with #clientId = aValue *before* #initialize starts to
Richard> execute.

The purpose of aClass>>#initialize is to make a "bare object" with the
internal state set up so that it can be *any* instance of that class.

If you want a specific state set from a class-side constructor, then you do as
has been said a few times in this thread already: call a (often private)
instance method that further tweaks the state.

"Foo class" makeWidgetWithX: x andY: y "instance creation"
    ^self basicNew initialize
      setX: x setY y;
      yourself.

"Foo" setX: anXInteger andY: aYInteger "private"
    x := anXInteger. "set instance var"
    y := aYInteger. "set instance var"
    "returns self, but we don't care"

Then you call

     myFoo := Foo makeWidgetWithX: 123 andY: 45.

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<[hidden email]> <URL:http://www.stonehenge.com/merlyn/>
Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!

Reply | Threaded
Open this post in threaded view
|

RE: Stupid Question?

Ron Teitelbaum
In reply to this post by Richard Eng
Hi Richard,

There are no Stupid ...  well you know.  

I thought I'd add to this thread with another answer.

There are plenty of ways to pass information into initialize.  You can use
any information that already exists and then just reference it in
initialize.

For example say you have some parameter that your application sets and you
want to use the value of that parameter in your class.

You could set your initialize to do something like this.

MyDomainObject>>initialize
        "set initial values"
        super initialize.
        self myApplicationParameter: MyApplicationParameterClass
someParameter.


As long as you use information that exists somewhere else you can reference
it.

The issue that people are trying to point out is that if your information is
not static and changes with each instantiation then you are better building
an instance creation method.  This method moves allows you to setup an
object the way you need it during creation.  

For example

MyDomainObject class>>newWithApplicationParameter: aParameter
        "return to the sender an instance of MyDomainObject"
        ^self new
                myApplicationParameter: aParameter;
                yourself

Now instead of calling:
        aDomainObject := MyDomainObject new.

You call
        aDomainObject := MyDomainObject newWithApplicationParameter:
MyApplicationParameterClass someParameter.

This makes much more sense since many people expect that initialize sets
either default values or sets up ivars with proper classes.

For Example you might use initialize to do something like this.

MyDomainObject>>initialize
        "set initial values"
        super initialize.
        self collectionOfValues: OrderedCollection new.
        self initialState: #new.
        self applicationParameterHolder: (MyApplicationParameterHolder
newFor: self).

Hope that helps!

Happy Squeaking

Ron Teitelbaum
President / Principal Software Engineer
US Medical Record Specialists


> From: Richard Eng
>
> I have a stupid question:  How do you pass information into the
> #initialize
> method at object creation time? You can't use any of the instance methods
> or
> accessors because they don't yet exist! So how do you pass information in?
>
> Thanks,
> Richard
>
>



Reply | Threaded
Open this post in threaded view
|

Re: Stupid Question?

Laurence Rozier
In reply to this post by Richard Eng
Though many of the comments have touched on the key points, you might find it useful to look at Kent Beck's Smalltalk Best Practice Patterns book which really covers this and other topics well. It's definitely not a stupid question and one has to think about the downstream implications of choosing an approach particularly wrt subclasses. Because of that I tend to use a variation of the initializeWith: approach that  looks something like:

materializeUsing: aDictionary

    self beforeMaterializing: aDictionary.
    self initializeUsing: aDictionary.
    self afterMaterializing: aDictionary


In Object, beforeMaterializing: and afterMaterializing: do nothing and
initializeUsing: simply calls initialize. Having before and after hooks makes it easier to evolve the class. You can use this approach with many existing classes, though you may have to be careful to understand how a class's initialize really works.

Then on there are two class side methods,

materializeUsing: aDictionary
^self basicNew materializeUsing: aDictionary

materialize
^self materializeUsing: Dictionary new.


The actual code in my framework is slightly more complicated but not by much. There is some overhead but for me it's a small price to pay for the consistency and flexibility it buys.

HTH,

Laurence

On Jan 16, 2008 8:46 AM, Richard Eng <[hidden email]> wrote:
I have a stupid question:  How do you pass information into the #initialize
method at object creation time? You can't use any of the instance methods or
accessors because they don't yet exist! So how do you pass information in?

Thanks,
Richard






Reply | Threaded
Open this post in threaded view
|

Re: Stupid Question?

timrowledge
In reply to this post by Zulq Alam-2
>
> Richard Eng wrote:
>> I'm not finding this to be true. I have a class #GSAssignmentList.  
>> It has
>> instance variable #clientId and accessor #clientId:. I do the  
>> following:
>>    self call: (GSAssignmentList new clientId: aValue)
>> In the #initialize method for GSAssignmentList, I write to the  
>> Transcript:
>>    Transcript cr; show: 'RKE: clientId = ', clientId asString.
>> It shows 'nil'.

Of course it does. You've simply written the code incorrectly.
GSAssignmentList new
        creates a new GSAssignmentList instance with all instance variables  
set to nil.
        sends #initialize to that new instance.
        returns the new instance
... and then....
(new instance) clientId: aValue
        presumably sets the clientId instance variable to aValue. Do remember  
that you don't need to name them the same. Nothing wrong with having a  
method named #fred: that sets the value of an instvar named wilma.

So if you report the value of clientId as part of an #initialize  
method, what value would you expect? How about 'nil'? Unless you  
actually explicitly set clientId in the initialize method before you  
show it on the Transcript how could you expect it to be anything else?

Smalltalk syntax is very simple and concise
unary
binary
keyword
left to right
parentheses limit local scope as in most syntaxes

tim
--
tim Rowledge; [hidden email]; http://www.rowledge.org/tim
Oxymorons: Business ethics